Django Rest Framework different image size for different account tiers (Basic, Premium)

Question:

There are three bultin account tiers: Basic, Premium and Enterprise:
Users that have "Basic" plan after uploading an image get:

  • a link to a thumbnail that’s 200px in height
    Users that have "Premium" plan get:
  • a link to a thumbnail that’s 200px in height
  • a link to a thumbnail that’s 400px in height
  • a link to the originally uploaded image

I have no idea how I can combine the ability to save different resolutions of photos added by the user depending on their membership.
My solution saves one resolution for all users.

models.py

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from PIL import Image


def user_directory_path(instance, filename):
    return 'images/{0}'.format(filename)


class Images(models.Model):

    title = models.CharField(max_length=250)
    image = models.ImageField(upload_to=user_directory_path)
    created = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.PROTECT, related_name='author')

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        img = Image.open(self.image.path)

        if img.height > 200:
            output_size = (200, 200)
            img.thumbnail(output_size)
            img.save(self.image.path)


class Profile(models.Model):

    MEMBERSHIP = (
        ('BASIC', 'Basic'),
        ('PREMIUM', 'Premium'),
        ('ENTERPRISE', 'Enterprise')
    )

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    membership = models.CharField(max_length=10, choices=MEMBERSHIP, default='BASIC')

    def __str__(self):
        return f'{self.user.username} {self.membership} Profile'

serializers.py

from rest_framework import serializers
from blog.models import Images, Profile



class ImagesSerializer(serializers.ModelSerializer):

    class Meta:
        model = Images
        fields = ('author', 'title', 'image')


views.py

class ImagesViewSet(viewsets.ModelViewSet):

    queryset = Images.objects.all()
    serializer_class = ImagesSerializer

    def get_queryset(self):

        user = self.request.user
        return Images.objects.filter(author=user)

Asked By: Robert Bielicki

||

Answers:

I think you need to expand your model and save images in the database in all resolutions:

# models.py
class Images(models.Model):

    title = models.CharField(max_length=250)
    image = models.ImageField(upload_to=user_directory_path)
    image_200 = models.ImageField(upload_to=user_directory_path_200)
    image_400 = models.ImageField(upload_to=user_directory_path_200)
    
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        img_200 = Image.open(self.image.path)
        img_400 = Image.open(self.image.path)

        output_size_200 = (200, 200)
        output_size_400 = (400, 400)
        img_200.thumbnail(output_size_200)
        img_400.thumbnail(output_size_400)
        img_200.save(self.image_200.path)
        img_400.save(self.image_400.path)

Then you need to add serialization depending on user privileges, something like this:

# serializers.py
class ImagesBasicUserSerializer(serializers.ModelSerializer):

    class Meta:
        model = Images
        fields = ('author', 'title', 'image_200')


class ImagesPremiumUserSerializer(serializers.ModelSerializer):

    class Meta:
        model = Images
        fields = ('author', 'title', 'image_200', 'image_400', 'image')

And then serialize the data depending on the user’s privileges by overriding the get_serializer_class method in the likeness of this:

# views.py
class ImagesViewSet(viewsets.ModelViewSet):

    queryset = Images.objects.none()
    serializer_class = ImagesBasicUserSerializer
    
    def get_user(self):
        
        user = self.request.user
        return user

    def get_serializer_class(self):
        
        user = self.get_user()
        if user.membership == 'Basic':
            return ImagesBasicUserSerializer
        if user.membership == 'Premium':
            return ImagesPremiumUserSerializer
    
    def get_queryset(self):

        user = self.get_user()
        return Images.objects.filter(author=user)
Answered By: user510170