Django imagekit processor: use dimensions stored in database

I have a model where thumbnail width varies between parent objects (ForeignKey). I need to be able to pass this information to the imagekit processors. This is what I have:

class Wall(models.Model):
    #...
    width = models.SmallIntegerField(null=True, blank=True)
    #...


class Poster(models.Model):
    wall = models.ForeignKey(Wall, related_name='posters')
    #...
    original_image = models.ImageField(upload_to=upload_image_to)

    def __init__(self, *args, **kwargs):
        self.thumbnail = ImageSpecField([
                Adjust(contrast=1.2, sharpness=1.1),
                SmartResize(height=163, width=self.wall.width)
            ],
            image_field='original_image', format='PNG'
        )

        super(Poster, self).__init__(*args, **kwargs)
    #...

      

But if I do that, nothing happens, not even the thumbnail url is generated.

And this will throw this exception:
AttributeError: 'ForeignKey' object has no attribute 'width'

class Poster(models.Model):
    wall = models.ForeignKey(Wall, related_name='posters')
    #...
    original_image = models.ImageField(upload_to=upload_image_to)

    thumbnail = ImageSpecField([
            Adjust(contrast=1.2, sharpness=1.1),
            SmartResize(height=163, width=wall.width)
        ],
        image_field='original_image', format='PNG'
    )
    #...

      

+3


source to share


2 answers


You cannot reference instance values ​​in a model definition. This is where it got a little tricky with Django; Models are a declaration of what an instance will look like when instantiated, so fields that are interdependent must refer to other fields by name, such as a BOM image_field='original_image'

.

Depending on the source for the imagekit, you can see that it processors

can either accept a list of static processors in use, or accept callable calls that should return a list of processors to apply during generation. Since you want the generation to change at runtime based on the width, you can use it to your advantage.

The processors

callee is called with an instance in which a box appears thumbnail

, which then allows you to search for the width.



def thumbnail_processors(instance, file):
    # Dynamic width lookup.
    width = instance.wall.width
    return [
        Adjust(contrast=1.2, sharpness=1.1),
        SmartResize(width=width, height=163),
        ]


class Poster(models.Model):
    wall = models.ForeignKey(Wall, related_name='posters')
    #...
    original_image = models.ImageField(upload_to=upload_image_to)

    thumbnail = ImageSpecField(
        processors=thumbnail_processors,
        image_field='original_image', format='PNG'
    )
    #...

      

Now when you access the field is called thumbnail_processors

to get a list of processors at runtime, not in the model declaration. width

is obtained from your foreign key and resized accordingly.

There are probably some bugs that will need investigation. When you access thumbnail

, the image file will be created according to your width. If you later change the width and request the thumbnail again, I'm not sure how the storage and caching backend will behave. You will probably need a custom file name generator that can encode the width of the thumbnail so that when the width changes, a new thumbnail is generated with a different name.

+4


source


# 1 answer does not match the current version of django-imagekit (3.0.3). And I found an official solution. Please refer to http://django-imagekit.readthedocs.org/en/latest/advanced_usage.html#specs-that-change



+5


source







All Articles