pythondjangodjango-rest-frameworkcelery

Get Image Field Absolute Path in Django Rest Framework - Non Request Flows


I've a periodic celery task which needs to store representation of a object in a specific json field.

Here is the simplified model structure. Parent <-- ChildWrapper <-- Child Image

So basically I've a 'ChildImage' model referring to 'ChildWrapper' which in turn refers to 'Parent'.

class Parent(TimeStampedModel):
    label = models.CharField(max_length=30, unique=True)
    live_content = JSONField(blank=True, null=True)
    is_template = models.BooleanField(default=False)
    reference_image = models.ImageField(upload_to=get_web_row_reference_image_path, blank=True, null=True)
    # Around 8 Other Fields

    def __str__(self):
        return '%s' % self.label


class ChildWrapper(TimeStampedModel):
    name = models.CharField(max_length=25, blank=True, null=True)
    row = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='web_column')
    order = models.PositiveIntegerField(default=0)
    # Around 20 Other Fields

    def __str__(self):
        return '%s' % self.name


class ChildImage(TimeStampedModel):
    image = models.ImageField(upload_to=get_web_image_path)
    column = models.ForeignKey(ChildWrapper, on_delete=models.CASCADE, related_name='web_image')
    # Around 10 Other Fields
 
    def __str__(self):
        return '%s' % self.column

This is the serializers defined for the models.

class ChildImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ChildImage
        fields = '__all__'

class ChildWrapperSerializer(serializers.ModelSerializer):
    web_image = ChildImageSerializer(read_only=True, many=True)
    class Meta:
        model = ChildWrapper
        fields = '__all__'

class ParentSerializer(serializers.ModelSerializer):
    web_column = ChildWrapperSerializer(many=True, read_only=True)
    class Meta:
        model = Parent
        fields = '__all__'

Here is the periodic celery task which does the required

@app.task(bind=True)
def update_data(self):
    # Get Parent By a condition.
    parent = Parent.objects.filter(to_update=True).first()

    parent.live_content = None
    parent.live_content = ParentSerializer(parent).data
    print(parent.live_content)
    parent.save()

The above task gets output of child image something like this with imagefield being relative path instead of absolute path.

{
    "id": 1
    "image": '/api/col/info.jpg'
}

Is there any way to get the absolute path for the image field?

{
    "id": 1
    "image": "http://localhost:8000/admin/media/api/col/info.jpg"
}

PS: I cannot pass Request context to serializer as ParentSerializer(parent, context={'request': request}) as there is no request object involved here.


Solution

  • Got it working,

    Added MEDIA_URL to my settings file as mentioned here.

    It seems DRF uses MEDIA_URL as a default prefix for urls(FileField & ImageField), even for non request/response flows.

    Since I had a different settings file for staging, development and production it was easier for me to set different URLs for each environment.

    Even though I'm not using 'django-versatileimagefield' library, the suggestion there still worked.