Django Wagtail динамическое меню на основе пользователя и роли пользователя
Использование Django-Wagtail и Wagtail Menu's. Я хочу построить систему со следующими типами характеристик.
- У меня есть класс пользователей (Vendor, Supplier) .
- Каждый созданный пользователь должен быть одним из этих двух классов.
- Каждый класс пользователей имеет различные роли, и эти роли отличаются от класса к классу. Например. Поставщик: финансы, склад, администратор Поставщик: финансы, склад, администратор, водитель.
Я создал класс UserType и оба класса "Vendor" и "Supplier" наследуются от этого класса. Затем я добавил поле в класс User, которое выбирает тип пользователя.
class UserType(model.Model):
common fields.......
class Vendor(UserType):
child_vendor_only_fields.....
class Supplier(UserType):
child_supplier_only_fields.....
class User(AbstractUser):
userVar = models.ForeignKey(UserType, on_delete=models.SET_NULL, null=True, blank=True)
Я также использовал админку wagtail для создания пользовательских ролей для каждого из этих классов, как описано выше.
Очевидно, что то, что "Поставщики" могут создавать, читать, обновлять и удалять, отличается от того, что может делать "Поставщик". И еще в рамках этого то, что финансовая роль может делать в "Поставщике", отличается от того, что может делать "Склад".
Как мне создать динамическое меню, которое отображает различные меню для этих перестановок?
Мои первоначальные мысли были навеяны этим. Простое добавление поля выбора
USER_TYPE_CHOICES = (
('Vendor', 'Vendor'),
('Supplier', 'Suplier'))
class GenericPage(MenuPage):
"""
This model will gain the fields, methods and `setting_panels` attribute
from `MenuPage`, but `settings_panels` is being overridden to include
other fields in the `Settings` tab.
"""
availableTo = CharField(choices=USER_TYPE_CHOICES,)
# 'menupage_panel' is a collapsible `MultiFieldPanel` with the important
# fields already grouped together, making it easy to include in custom
# panel definitions, like so:
settings_panels = [
FieldPanel('custom_settings_field_one'),
menupage_panel
]
У меня два вопроса:
Правильно ли я выбрал путь создания пользовательских меню для типов пользователей? Если да, то как мне потом сделать то же самое для ролей под типами пользователей?
- В плане CRUD я должен просто реализовать проверку каждый раз, когда пользователь делает грубое действие, может ли он зафиксировать это действие прагматически?
Что касается CRUD, я не сторонник того, чтобы давать кому-то возможность сделать что-то, а потом сообщать, что эта возможность запрещена. Они могут потратить полчаса на создание/редактирование страницы, а потом узнать, что потратили это время впустую. Лучше сказать им об этом при загрузке страницы.
Для типов пользователей я бы просто создал их как роли, в которые вы добавляете пользователей. Тогда у вас будет простой тест для user.groups, чтобы увидеть, какую роль они имеют.
Вы можете легко разработать пользовательскую панель с ограничениями для каждого из типов панелей, которые вам нужно ограничить, проще, если все они FieldPanels. В классе BoundPanel у вас есть доступ к объекту запроса, поэтому вы можете извлечь объект пользователя из него во время выполнения и решить, что делать дальше.
У Panel.BoundPanel есть метод is_shown(), поэтому вы можете создать пользовательскую панель, наследующую FieldPanel, переопределить этот метод, чтобы проверить, есть ли в запросе пользователя параметр авторизованного списка и установить true/false соответственно.
# restricted_field_panel.py
from wagtail.admin.panels import FieldPanel
class RestrictedFieldPanel(FieldPanel):
def __init__(self, field_name, authorised_groups, **kwargs):
self.field_name = field_name
self.authorised_groups = authorised_groups if isinstance(authorised_groups, list) else [authorised_groups]
super().__init__(self.field_name, **kwargs)
def clone_kwargs(self):
kwargs = super().clone_kwargs()
kwargs.update(
authorised_groups=self.authorised_groups
)
return kwargs
class BoundPanel(FieldPanel.BoundPanel):
def is_shown(self):
show_field = super().is_shown()
is_authorised = self.request.user.groups.get_queryset().filter(name__in=self.panel.authorised_groups).exists()
return (show_field and is_authorised)
В модели страницы:
content_panels = Page.content_panels + [
RestrictedFieldPanel('some_vendor_field', 'Vendors'),
RestrictedFieldPanel('some_supplier_field', 'Suppliers'),
....
]
Для авторизованных групп вы можете добавить роль администратора сайта по умолчанию, чтобы администраторы сайта всегда видели все ограниченные панели независимо от этого.
Другие типы панелей нужно наследовать и тестировать везде, где выполняется рендеринг.