matthewwithanm / django-imagekit

Automated image processing for Django. Currently v4.0
http://django-imagekit.rtfd.org/
BSD 3-Clause "New" or "Revised" License
2.26k stars 276 forks source link

How to get value from ForeignKey field to the custom ImageKit processor? #445

Closed koddr closed 6 years ago

koddr commented 6 years ago

Hello. Little question is "how to get value from ForeignKey field to the custom ImageKit processor?"

My models.py:

# ./example/models.py

from imagekit.models import ImageSpecField

class Example(models.Model):
    description = models.CharField('Description', ...)
    image = models.ImageField('Picture', ...)

    image_800x800 = ImageSpecField(
        source='image',
        id='tours:tours:image_800x800'
    )

class ExampleSecond(models.Model):
    example = models.ForeignKey(Example, related_name='info', ...)
    name = models.CharField('Name', ...)
    ...

My custom processor:

# ./example/processors.py

from django.conf import settings
from PIL import Image, ImageDraw, ImageFont
from imagekit import ImageSpec, register
from imagekit.utils import get_field_info

_default_font = ImageFont.truetype(settings.TEXT_OVERLAY_FONT_REGULAR, 24)

def add_text_overlay(image, text, font=_default_font):
    rgba_image = image.convert('RGBA')
    text_overlay = Image.new('RGBA', rgba_image.size, (255, 255, 255, 0))

    image_draw = ImageDraw.Draw(text_overlay)
    text_size_x, text_size_y = image_draw.textsize(text, font=font)
    text_xy = ((rgba_image.size[0] / 2) - (text_size_x / 2), (rgba_image.size[1] / 2) - (text_size_y / 2))

    image_draw.text(text_xy, text, font=font, fill=(255, 255, 255, 255))
    image_with_text_overlay = Image.alpha_composite(rgba_image, text_overlay)

    return image_with_text_overlay

class TextOverlayProcessor(object):
    def __init__(self, text='Lorem ipsum dolor sit amet'):
        """
        :param text: The overlay text, string.

        """
        self.text = text

    def process(self, img):
        return add_text_overlay(image=img, text=self.text)

@register.generator('example:example:image_800x800')
class TextOverlayImage(ImageSpec):
    format = 'JPEG'
    options = {'quality': 100}

    @property
    def processors(self):
        model, field_name = get_field_info(self.source)
        return [
            ResizeToFill(800, 800),
            TextOverlayProcessor(text=model.info[0].name) # rise 'RelatedManager' object does not support indexing
        ]

But how to get name field value from ExampleSecond model for place to TextOverlayProcessor attribute?

I will be glad to explanatory comments and/or use cases.

koddr commented 6 years ago

In my case, I just call to ForeignKey model from DB in generator. But I don't know, it's right way?

Like this:

@register.generator('example:example:image_800x800')
class TextOverlayImage(ImageSpec):
    format = 'JPEG'
    options = {'quality': 100}

    @property
    def processors(self):
        model, field_name = get_field_info(self.source)

        # Call to DB
        info = ExampleSecond.objects.filter(id=model.id)

        return [
            ResizeToFill(800, 800),
            TextOverlayProcessor(text=info.name)
        ]
vstoykov commented 6 years ago

Your question is not related to ImageKit. You already found out how to get the model instance with get_field_info which is specific to ImageKit. After that you are using pure Django ORM functionality which is not related to ImageKit at all.

In your case model is not a model but actually an instance of the model. Also as the exception i saying 'RelatedManager' object does not support indexing. This is because you can't do:

instance = Example.objects.get(pk=some_pk)
info = instance.info[0]

You can change that to:

info = instance.info.all()[0]

If you will have only one info then you can replace it with:

info = instance.info.get()

or directly change your model to represent that you have only one info by using OneToOneField:

example = models.OneToOneFIeld(Example, related_name='info', ...)

and then accesing it directly with:

info = instance.info

You can read more in the Django documentation https://docs.djangoproject.com/en/1.11/ref/models/relations/