Condition setting problem over custom build decorator in Django

Viewed 60

I am trying to make a custom build decorator in Django.

my models.py:

class myCustomeUser(AbstractUser):
    id = models.AutoField(primary_key=True)
    username = models.CharField(max_length=20, unique="True", blank=False)
    password = models.CharField(max_length=20, blank=False)
    is_Inspector = models.BooleanField(default=False)
    is_Industry = models.BooleanField(default=False)
    is_Admin = models.BooleanField(default=False)

    def __str__(self):
        return self.username

class Inspector(models.Model):
    user = models.ForeignKey(myCustomeUser, on_delete=models.CASCADE, related_name='inspector_releted_user')
    name = models.CharField(max_length=200, blank=False, null=True)
    gmail = models.EmailField(null=True, blank=False, unique=True)
    nid = models.IntegerField(blank=False, unique=True)
    inspector_varified = models.BooleanField(default=False, blank=True, null=True)

    def __str__(self):
        return self.name

Now I want to build a decorator that will allow the user to pass by satisfying the following 3 conditions:

  1. user is active and logged in
  2. is_Inspector value is True
  3. inspector_varified's value is also True (inspector_varified is in under Inspector class)

my decorators.py:

def inspector_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='app2:request_login'):
    actual_decorator = user_passes_test(
        lambda u: u.is_active and u.is_Inspector,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

It is maintaining conditions 1 & 2, but condition-3 is not satisfied by it. How can I code for it also?

1 Answers

The modeling itself does not make much sense: by using a ForeignKey, a User can have multiple Inspector objects, so there is no single Inspector. Likely that is not how you want to model this.

You can convert the ForeignKey into a OneToOneField [Django-doc], this is in essence a ForeignKey with a uniqness constraint, so that means that each Inspector will refer to a different user.

class Inspector(models.Model):
    user = models.OneToOneField(
        myCustomeUser,
        on_delete=models.CASCADE,
        related_name='inspector_releted_user'
    )
    # …

then we can check this with:

def check(user):
    try:
        return user.is_authenticated and user.is_Inspector and user.inspector_related_user.inspector_varified
    except AttributeError:
        return False

then we can validate this with:

def inspector_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='app2:request_login'):
    actual_decorator = user_passes_test(
        check,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

Still however the modeling does not look very good, especially since is_Inspector does not need to be a field of the user model: we can simply check if a User is an inspector by checking if there is an Inspector object which points to that user.

Furthermore field names are written in snake_case, so is_inspector, not is_Inspector.

Related