Создание собственного декоратора в Django для разных разрешений

Опубликовано: 21 Января, 2023

Декораторы — невероятно полезные инструменты, которые позволяют вам динамически изменять функциональность функции, метода или класса без необходимости прямого использования подклассов или изменения исходного кода функции. Параметры декоратора login_required, require HTTP, require POST и другие необходимы при работе с представлениями Django.

Но есть также ситуации, когда мы хотим использовать наши собственные декораторы с уникальным дизайном, которые функционируют именно так, как мы хотим. Создание декораторов также может быть полезным, если вы применяете одну и ту же логику в нескольких местах и обнаружите, что удалить и добавить декоратор просто после того, как ваши изменения будут завершены.

Создайте собственный декоратор в Django

Здесь мы настроим механизм доступа учащихся к сайту. Чтобы учащиеся, учителя и директора не могли получить доступ к страницам, доступным для других пользователей. Этими привилегиями будут управлять настраиваемые декораторы, которые мы создадим, и мы будем возвращать различные результаты/ответы при каждом доступе к странице, чтобы мы могли увидеть различные способы перенаправления или возврата ответа для недоступной страницы.

Пошаговая реализация

Шаг 1: Создайте виртуальную среду и установите Django.

python -m venv custom_decorator_venv

Шаг 2. Создайте проект с именем CustomDecorator.

django-admin startproject CustomDecorator

Шаг 3. Перейдите в папку CustomDecorator, а затем создайте приложение с именем пользователя в проекте.

cd CustomDecorator
python manage.py startapp user

Структура файла

Это окончательная файловая структура после выполнения всех шагов.

Шаг 4: Добавьте пользовательское приложение в файл INSTALLED_APPS.

Python3




INSTALLED_APPS = [
    "user.apps.UserConfig",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",

Шаг 5. Установите эту модель в качестве модели аутентификации по умолчанию в settings.py.

Python3




AUTH_USER_MODEL = "user.UserAccount"

Шаг 6: Мы создадим UserAccountManager в качестве менеджера для модели UserAccount. В модели UserAccount будет пять функций: создать пользователя, создать суперпользователя, создать учителя, создать ученика и создать директора. Если логическое значение student равно True, пользователь является студентом; если логическое значение учителя равно True, пользователь является учителем; и то же самое верно для принципала.

пользователи/models.py

Python3




from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
  
  
class UserAccountManager(BaseUserManager):
    def create_user(self, email, username, password=None):
        if not email:
            raise ValueError("Email field is required !")
        if not username:
            raise ValueError("Username field is required !")
        if not password:
            raise ValueError("Passowrd field is required !")
        user = self.model(
            email=email,
            username=username
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
  
    def create_superuser(self, email, username, password):
        user = self.create_user(
            email=email, username=username, password=password)
        user.is_superuser = True
        user.is_staff = True
        user.is_admin = True
        user.save()
        return user
  
    def create_student(self, email, username, password):
        user = self.create_user(email, username, password)
        user.is_student = True
        user.save()
        return user
  
    def create_teacher(self, email, username, password):
        user = self.create_user(email, username, password)
        user.is_teacher = True
        user.save()
        return user
  
    def create_principal(self, email, username, password):
        user = self.create_user(email, username, password)
        user.is_principal = True
        user.save()
        return user
  
  
class UserAccount(AbstractBaseUser):
    username = models.CharField(max_length=200, blank=False, null=False)
    email = models.CharField(
        max_length=200, blank=False, null=False, unique=True)
  
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
  
    is_student = models.BooleanField(default=False)
    is_teacher = models.BooleanField(default=False)
    is_principal = models.BooleanField(default=False)
  
    objects = UserAccountManager()
  
    USERNAME_FIELD = "email"
  
    def __unicode__(self):
        return str(self.username)
  
    def has_perm(self, perm, obj=None):
        return self.is_admin
  
    def has_module_perms(self, app_label):
        return True

Шаг 7: Создайте папку templates/user в пользовательском приложении, в которой будут храниться следующие шаблоны:

  • пользователь/шаблоны/пользователь/homePage.html

Это для главной страницы сайта.

HTML




<!DOCTYPE html>
  
<html>
    <body>
        {% if messages %}
            {% for message in messages   %}
  
                <div style = "color: red;">{{message}}</div>
  
            {% endfor %}
            <br>
            <br>
        {% endif %}
        {% if request.user.is_authenticated %}
        <h1> {{request.user.email}}</h1>
        <br>
  
            {% if request.user.is_student %}
  
                You are a student ...
  
            {% elif request.user.is_teacher %}
  
                You are a teacher ...
              
            {% elif  request.user.is_principal %}
  
                You are a principal ...
              
            {% else %}
  
                You don"t have any privilege ...
  
            {% endif %}
              
        {% endif %}
  
        <br>
        <br>
        <a href = "{% url  "user_urls:login-user" %}">Login </a>
        <br>
        <br>
        <a href = "{% url  "user_urls:student-view" %}">Student View </a>
        <br>
        <br>
        <a href = "{% url  "user_urls:teacher-view" %}">Teacher View</a>
        <br>
        <br>
        <a href = "{% url  "user_urls:principal-view" %}">Principal View</a>
        <br>
        <br>
  
    </body>
</html>

  • пользователь/шаблоны/пользователь/loginView.html

Это домашняя страница, сообщающая, какой вы пользователь, и есть ссылки на другие страницы сайта, мы создадим эти ссылки и представления, а также отобразим сообщения, если они есть.

HTML




{% if messages %}
  
    {% for message in messages %}
  
        <div style = "color: red ;">{{message}}</div>
        <br>
  
    {% endfor %}
  
{% endif %}
  
<form method = "post">
    {% csrf_token %}
{{form.as_p}}
<br>
<br>
<input type = "submit" value = "Login" />
</form>

  • пользователь/шаблоны/пользователь/principalView.html

Это представление, доступ к которому будет иметь только пользователь, являющийся принципалом.

HTML




<h1> {{request.user.email}}</h1>
<br>
<h1>
    You are a principal and you can access the page !
</h1>

  • пользователь/шаблоны/пользователь/studentView.html

Это представление студента, доступ к которому может получить только студент.

HTML




<h1> {{request.user.email}}</h1>
<br>
<h1>
    You are a student and you can access the page !
</h1>

  • пользователь/шаблоны/пользователь/teacherView.html

Это точка зрения учителя, которую может видеть только учитель.

HTML




<h1> {{request.user.email}}</h1>
<br>
  
<h1>
    You are a teacher and you can access the page !
</h1>

Шаг 8: user/decorators.py

Понимание концепции декораторов для этого проекта

Перед созданием нашего настоящего декоратора необходимо понять, как построить декоратор, это псевдокод/скелет декоратора.

У нас есть функция с именем test_function, которая принимает необходимые аргументы в зависимости от обстоятельств и возвращает True или False. Однако вы можете написать свою собственную функцию и определить любой оператор, который вам нравится. Декоратор либо принимает, либо отклоняет аргумент в зависимости от ситуации. @wraps из модуля functool берут имя функции, которое должно быть декорировано функцией-оболочкой.

_wrapped_view (request, *args, **kwargs) — это точное представление, в которое будет завернут декоратор, это как бы клон представления, вокруг которого будет завернуто декоратор, теперь вы можете выполнять любые действия, например, вы можете перенаправить , вернуть любой ответ или двигаться дальше.

Python3




from functool import wraps
  
  
def test_function_works(*args, **kwargs):
      if args[0] == True:
      return True
    return False
  
def some_decorator(*decorator_args , **decorator_kwargs):
    def decorator(view_function):
        @wraps(view_function)
        def _wrapped_view(request, *view_args, **view_kwargs):
            print("The required actions will be taken here ! Well,
            actually inside the _wrapped_view function")
              
            if not test_function_works(*arguments , **keyword_arguuments):
                print("The necessary operation that will be taken if
                        the test case fails !")
                  
            return view_function(request, *args, **kwargs)
        return _wrapped_view
    return decorator