User passes test in django to check subscription

I have a django application where I need to check if a user has a valid subscription, otherwise it redirects the user to his/her dashboard. I was thinking to use the django decorator user_passes_test but I couldn't find a proper way to create the function to check the user. My models for user and subscription are:

class CustomUser(AbstractUser):
    user_type_data = (
    ('admin', 'admin'),
    ('school_admin', 'school_admin'),
    ('student', 'student'),
)
    user_type = models.CharField(
    max_length=20, choices=user_type_data, default='student')
    address = models.CharField(max_length=500, null=True, blank=True)
    city = models.CharField(max_length=200, null=True, blank=True)
    zip_code = models.CharField(max_length=100, null=True, blank=True)
    country = CountryField(null=True, blank=True)
    phone = models.CharField(max_length=200, null=True, blank=True)
    selected_course = models.ForeignKey(QuizTheoryCourse, on_delete=models.CASCADE, null=True, blank=True)

class Subscription(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    issue_date = models.DateTimeField(null=True, blank=True)
    duration = models.IntegerField(choices=DURATION_CHOICES)
    expiration_date = models.DateTimeField()


def __str__(self):
    return f'{self.user} - {str(self.expiration_date)}'

def get_expiration(self):
    if self.expiration_date:
        if self.expiration_date > timezone.now():
            expiration_date = self.expiration_date + timedelta(days=int(self.duration))
        else:
            expiration_date = dt.now() + timedelta(days=int(self.duration))
    else:
        expiration_date = dt.now() + timedelta(days=int(self.duration))
    return expiration_date


def is_subscription_valid(self):
    today = timezone.now()
    return today < self.expiration_date

The function I am using to pass in the decorator is:

def subscription_valid(user):
    try:
        superuser = user.is_superuser
        user_valid = user.subscription.is_subscription_valid
        return superuser or user_valid
    except user.DoesNotExist:
        return False

My problem is that, anytime the user doesn't have any kind of subscription (let's say it's just registered) I receive an error:

CustomUser has no subscription.

I suppose I have some kind of if/elif statement in the function, but I couldn't figure out how to get around it.

Your idea is good, but there are some erros in your function. When you try to access to subscription, Django can raise a ObjectDoesNotExist, not a model.DoesNotExist exception. You can check if subscription exist by using hasattr(user, 'subscription') or try an access and catch the exception

from django.core.exceptions import ObjectDoesNotExist
def subscription_valid(user):
    try:
        superuser = user.is_superuser
        user_valid = user.subscription.is_subscription_valid
        return superuser or user_valid
    except ObjectDoesNotExist:
        return False

Back to Top