Django 1.11 – How to use height_field and width_field with ImageField

Question:

I’ve the defined the following model which it’s used in my Django application for storing the images with different dimensions.

class Image(models.Model):

    def _img_path(instance, filename):
        # file will be uploaded to MEDIA_ROOT/<instance.path>/<filename>
        return '{0}/{1}'.format(instance.path, filename)

    id = models.AutoField(primary_key=True)
    path = models.CharField(max_length=500)
    img = models.ImageField(upload_to=_img_path, max_length=500, height_field='img_height', width_field='img_width')
    img_md = models.ImageField(upload_to=_img_path, max_length=500, height_field='img_height', width_field='img_width', null=True)
    img_sm = models.ImageField(upload_to=_img_path, max_length=500, height_field='img_height', width_field='img_width', null=True)
    img_xs = models.ImageField(upload_to=_img_path, max_length=500, height_field='img_height', width_field='img_width', null=True)

Since I’m using the Django REST Framework for APIs, the following is the code of the serialiser that saves images:

class ProductDrawingSerializer(ModelSerializer):
    drawing = ImageSerializer()

    class Meta:
        model = ProductDrawing
        fields = [
            'product',
            'drawing',
        ]

    def create(self, validated_data):
        product = validated_data['product']
        filename = 'product-{0}.{1}'.format(product.pk, 'jpg')
        filename_xs  = 'product-{0}_{1}.{2}'.format(product.pk, 'xs', 'jpg')
        # resize_image() is just function I wrote that uses the Pillow Image.resize()
        resize_image(validated_data['drawing']['img'], 'temp_files/'+filename, max_w=1500.0, max_h=1500.0, max_file_size=0.7, to_jpeg=True)
        resize_image(validated_data['drawing']['img'], 'temp_files/'+filename_xs, max_w=120.0, max_h=120.0, max_file_size=0.01, max_img_quality=98, to_jpeg=True, do_trim=True)
        drawing = Image()
        drawing.path = 'drawings'
        drawing.img.save(filename, File(open('temp_files/'+filename, 'rb')), save=False)
        drawing.img_xs.save(filename_xs, File(open('temp_files/'+filename_xs, 'rb')), save=False)
        drawing.save()

        product_drawing = ProductDrawing(product=product,drawing=drawing)
        product_drawing.save()
        return product_drawing

I don’t know why, but I’m getting an AttributeError:

'Image' object has no attribute 'img_width'

Traceback:

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/api/products/1/drawings/add/

Django Version: 1.11.2
Python Version: 3.6.1
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'product',
 'brand']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  489.             response = self.handle_exception(exc)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
  449.             self.raise_uncaught_exception(exc)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  486.             response = handler(request, *args, **kwargs)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/generics.py" in post
  192.         return self.create(request, *args, **kwargs)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/mixins.py" in create
  21.         self.perform_create(serializer)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/mixins.py" in perform_create
  26.         serializer.save()

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/rest_framework/serializers.py" in save
  215.             self.instance = self.create(validated_data)

File "~/Documents/Django projects/myapp/product/api/serializers.py" in create
  202.         drawing.img.save(filename, File(open('temp_files/'+filename, 'rb')), save=False)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/db/models/fields/files.py" in save
  95.         setattr(self.instance, self.field.name, self.name)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/db/models/fields/files.py" in __set__
  377.             self.field.update_dimension_fields(instance, force=True)

File "/anaconda/envs/myapp-env/lib/python3.6/site-packages/django/db/models/fields/files.py" in update_dimension_fields
  464.             (self.width_field and not getattr(instance, self.width_field)) or

Exception Type: AttributeError at /api/products/1/drawings/add/
Exception Value: 'ImageModel' object has no attribute 'img_width'

I thought the attributes height_field and width_field were auto-popolutated.
How to proper use them?

Asked By: Fabio

||

Answers:

You need add columns to your model
with names equal values of the parameters: height_field, width_field

class Image(models.Model):

    img_width = models.PositiveIntegerField()
    img_height = models.PositiveIntegerField()

You can read here field-attribute and in the source ImageField

Answered By: Brown Bear