Search code examples
djangodjango-modelsdjango-rest-frameworkdjango-serializer

retrieving the last instance of a model in another model's modelSerializer in django rest framework


I am creating rest APIs for a website in which users can purchase one of the provided subscriptions.

In this website there is a user-info API which returns the information about the logged in user which can be used to show their info on the website. The problem is that, the mentioned API's serializer is a modelSerializer on the "User" model and the information that I want to return is the instance of "Subscription" model which the latest instance of "SubPurchase" model refers to.

These are my serializers, models and views.And I need to somehow return the user's current subscription's ID and name along with the user's information. If you have any further questions, ask me in the comments and I'll answer them.

# models.py
class User(AbstractBaseUser, PermissionsMixin):
    userID = models.AutoField(primary_key=True)
    username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
    email= models.EmailField(max_length=100, unique=True,  validators=[EmailValidator()])
    name = models.CharField(max_length=100)
    isSuspended = models.BooleanField(default=False)
    isAdmin = models.BooleanField(default=False)
    emailActivation = models.BooleanField(default=False)
    balance = models.IntegerField(default=0)

    objects = UserManager()

    USERNAME_FIELD = 'username'


class Subscription(models.Model):
    subID = models.AutoField(primary_key=True)
    nameOf = models.CharField(max_length=50)
    price = models.PositiveIntegerField()
    salePercentage = models.PositiveIntegerField(default=0)
    saleExpiration = models.DateTimeField(default=datetime.datetime.now, blank=True)

    def __str__(self):
        return f"{self.nameOf}"


class SubPurchase(models.Model):
    price = models.PositiveIntegerField()
    dateOf = models.DateTimeField(auto_now_add=True)
    
    user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    subscription = models.ForeignKey(Subscription, null=True, on_delete=models.SET_NULL)
    
    def __str__(self):
        return self.subscription
# serializers.py
class UserInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
        read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')


# views.py
class UserInfoViewSet(viewsets.ModelViewSet):
    queryset = get_user_model().objects.all()
    serializer_class = UserInfoSerializer

    def get_queryset(self):
        uID = getattr(self.request.user,'userID')
        return get_user_model().objects.filter(userID=uID)

    def get_object(self):
        uID = getattr(self.request.user,'userID')
        return self.queryset.filter(userID=uID)

Again, I need to change the UserInfoSerializer in a way that would give me the user's current subscription's name, ID and expiration date which would be 30 days after the purchase date


Solution

  • If you are only interested in the returned data, you can override the function to_representation of your serializer and create a serializer for your related model. If I understood correctly, the current subscription of your user is the last one (if sorted by "dateOf"). So something like that could do the trick

    class SubscriptionSerializer(serializers.ModelSerializer):
         class Meta:
               model = Subscription
               fields = ('nameOf', 'id', 'saleExpiration ')
    
    class UserInfoSerializer(serializers.ModelSerializer):
        class Meta:
            model = get_user_model()
            fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
            read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
    
        def to_representation(self, instance):
             data = super().to_representation(instance)
             current_subs = instance.subpurchase_set.order_by('dateOf').last().subscription
             data['current_subscription'] = SubscriptionSerializer(instance=current_subs).data
             return data