Разрешение группы подключено к списку моделей

Моя модель:

class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)

POSITIONS = (
    ("volunteer", "volunteer"),
    ("employee", "employee"),
    ("manager", "manager"),
    ("director", "director"),
    ("vet", "vet")
)
position = models.CharField(choices=POSITIONS, max_length=15)
picture = models.ImageField(blank=True, null=True)

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

1 ответ

Решение

Я бы использовал нестандартные декораторы. Вы можете использовать @method_decorator(decorator, name='dispatch'), Сначала вы должны создать файл decorators.py в каталоге приложения. В значительной степени происходит то, что декоратор метода вызывается перед представлением и передает функцию первому вызываемому объекту. Что мы на самом деле делаем, так это делаем вызываемую функцию вызываемой как проверку позиции и передаем аргумент позиции. Затем мы обрабатываем фактическую часть декоратора метода, которая передает аргумент функции в _method_wrapper. В этот момент мы выполняем наши вычисления так же, как и в представлении с переменной request в _wrapper callable.

# decorators.py
from django.core.exceptions import PermissionDenied
from app.models import UserProfile

def position_check(position):
    def _method_wrapper(function):
        def _wrapper(request, *args, **kwargs):
            try:
                user = UserProfile.object.get(user_id=request.user.id)
            except UserProfile.DoesNotExist:
                raise PermissionDenied
            if user.position == position:
                return function(request, *args, **kwargs)
            else:
                raise PermissionDenied
        return _wrapper
    return _method_wrapper

Теперь, на ваш взгляд, вы бы назвали это так.

# views.py
from app.decorators import position_check
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

@method_decorator(position_check('manager'), name='dispatch')
class HomeView(TemplateView):
    template_name = "home.html"

Единственная проблема, с которой я столкнулся, это необходимость наследовать разрешения. Я бы не стал определять ваш выбор так, как он у вас. Я бы установил фактическое значение на число, а часть выбора на ваше удобочитаемое, например, ниже. Это позволит вам устанавливать разрешения в зависимости от числового значения, так if user.position >= 3 директор тогда унаследует разрешения от менеджера.

POSITIONS = (
    (1, "volunteer"),
    (2, "employee"),
    (3, "manager"),
    (4, "director"),
    (5, "vet")
)
Другие вопросы по тегам