1

i am trying to define a field which being calculated based on user_type, I did the following method but its not working, if anyone can advise me to the correct approach.

so what i am trying to achieve here is to construct a method such as <user>.book_limit to return the maximum number of allowed books based on user_type

#models.py 

class UserProfile(models.Model):
    class UserType(models.TextChoices):
        FREE = 'FR', 'FREE'
        BASIC = 'BS', 'BASIC'
        PREMIUM = 'PR', 'PREMIUM'

    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    bio = models.CharField(max_length=255)
    created_on = models.DateTimeField(auto_now_add=True)
    last_updated = models.DateTimeField(auto_now=True)
    user_type = models.CharField(max_length=2, choices=UserType.choices, default=UserType.FREE)

    def __str__(self):
        return self.user.username

    @property
    def borrow_limit(self):
        return UserProfile.objects.annotate(book_limit=Case(
            When(user_type=UserProfile.UserType.FREE, then=Value('1')),
            When(user_type=UserProfile.UserType.BASIC, then=Value('2')),
            When(user_type=UserProfile.UserType.PREMIUM, then=Value('5')),
            default=Value('1'), output_field=IntegerField))
Ahmed Al-Haffar
  • 520
  • 4
  • 17

2 Answers2

2

You can use a manager to each time annotate the value:

from django.db.models import Case, IntegerField, Value, When

class UserProfileManager(models.Manager):

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).annotate(
            book_limit=Case(
                When(user_type=UserProfile.UserType.FREE, then=Value(1)),
                When(user_type=UserProfile.UserType.BASIC, then=Value(2)),
                When(user_type=UserProfile.UserType.PREMIUM, then=Value(5)),
                default=Value(1),
                output_field=IntegerField()
            )
        )

class UserProfile(models.Model):
    class UserType(models.TextChoices):
        FREE = 'FR', 'FREE'
        BASIC = 'BS', 'BASIC'
        PREMIUM = 'PR', 'PREMIUM'

    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    bio = models.CharField(max_length=255)
    created_on = models.DateTimeField(auto_now_add=True)
    last_updated = models.DateTimeField(auto_now=True)
    user_type = models.CharField(max_length=2, choices=UserType.choices, default=UserType.FREE)
    objects = UserProfileManager()
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

You can customize your initial queryset like described here.

Ali Asgari
  • 801
  • 7
  • 18