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))
2

2 Answers 2

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()
Sign up to request clarification or add additional context in comments.

3 Comments

you are the boss
but can you please explain how this works, why we add ars and kwargs for the get_queryset
@AhmedAl-Haffar: it means we pass all positional and named parameters to the super call. If you later for example add a mixin, then it can introuduce/consume parameters. See for example: stackoverflow.com/a/8973101/67579
1

You can customize your initial queryset like described here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.