kopia lustrzana https://github.com/wagtail/wagtail
Allow GroupViewSet to be customised (#6477)
rodzic
3f128b554e
commit
9dda314263
|
@ -0,0 +1,111 @@
|
|||
Custom group edit/create page
|
||||
=============================
|
||||
|
||||
Custom group edit/create page example
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This example shows how to customize group 'edit' and 'create' page in Wagtail
|
||||
admin.
|
||||
|
||||
Let's say you need to connect Active Directory groups with Django groups.
|
||||
So create a model for Active Directory groups.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import models
|
||||
|
||||
|
||||
class ADGroup(models.Model):
|
||||
guid = models.CharField(verbose_name="GUID", max_length=64, db_index=True, unique=True)
|
||||
name = models.CharField(verbose_name="Group", max_length=255)
|
||||
domain = models.CharField(verbose_name="Domain", max_length=255, db_index=True)
|
||||
description = models.TextField(verbose_name="Description", blank=True, null=True)
|
||||
roles = models.ManyToManyField(Group, verbose_name="Role", related_name="adgroups", blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "AD group"
|
||||
verbose_name_plural = "AD groups"
|
||||
|
||||
However, there is no role field on the Wagtail group 'edit' or 'create' page.
|
||||
To add it, inherit from Wagtail group form and add a new field.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django import forms
|
||||
|
||||
from wagtail.users.forms import GroupForm as WagtailGroupForm
|
||||
|
||||
from .models import ADGroup
|
||||
|
||||
|
||||
class GroupForm(WagtailGroupForm):
|
||||
adgroups = forms.ModelMultipleChoiceField(
|
||||
label="AD groups",
|
||||
required=False,
|
||||
queryset=ADGroup.objects.order_by("name"),
|
||||
)
|
||||
|
||||
class Meta(WagtailGroupForm.Meta):
|
||||
fields = WagtailGroupForm.Meta.fields + ("adgroups",)
|
||||
|
||||
def __init__(self, initial=None, instance=None, **kwargs):
|
||||
if instance is not None:
|
||||
if initial is None:
|
||||
initial = {}
|
||||
initial["adgroups"] = instance.adgroups.all()
|
||||
super().__init__(initial=initial, instance=instance, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = super().save()
|
||||
instance.adgroups.set(self.cleaned_data["adgroups"])
|
||||
return instance
|
||||
|
||||
Now add your custom form into group viewset by inheriting default Wagtail
|
||||
``GroupViewSet`` class and overriding ``get_form_class`` method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.users.views.groups import GroupViewSet as WagtailGroupViewSet
|
||||
|
||||
from .forms import GroupForm
|
||||
|
||||
|
||||
class GroupViewSet(WagtailGroupViewSet):
|
||||
def get_form_class(self, for_update=False):
|
||||
return GroupForm
|
||||
|
||||
Append the field into group 'edit'/'create' templates.
|
||||
|
||||
.. code-block:: html+Django
|
||||
|
||||
{% extends "wagtailusers/groups/edit.html" %}
|
||||
{% load wagtailusers_tags wagtailadmin_tags i18n %}
|
||||
|
||||
{% block extra_fields %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.adgroups %}
|
||||
{% endblock extra_fields %}
|
||||
|
||||
Finally configure ``wagtail.users`` application for using the viewset. Create
|
||||
``myapplication/apps.py`` module in the main application package and configure
|
||||
``AppConfig``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.users.apps import WagtailUsersAppConfig
|
||||
|
||||
|
||||
class CustomUsersAppConfig(WagtailUsersAppConfig):
|
||||
group_viewset = "myapplication.someapp.viewsets.GroupViewSet"
|
||||
|
||||
And put path to ``CustomUsersAppConfig`` into ``settings.INSTALLED_APPS``
|
||||
instead of ``wagtail.users``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
INSTALLED_APPS = [
|
||||
...,
|
||||
"myapplication.apps.CustomUsersAppConfig",
|
||||
# "wagtail.users",
|
||||
...,
|
||||
]
|
|
@ -11,5 +11,6 @@ Customising Wagtail
|
|||
extending_hallo
|
||||
admin_templates
|
||||
custom_user_models
|
||||
custom_group_viewset
|
||||
streamfield_blocks
|
||||
custom_account_settings
|
||||
|
|
|
@ -7,3 +7,4 @@ class WagtailUsersAppConfig(AppConfig):
|
|||
label = 'wagtailusers'
|
||||
verbose_name = _("Wagtail users")
|
||||
default_auto_field = 'django.db.models.AutoField'
|
||||
group_viewset = None
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
{% csrf_token %}
|
||||
|
||||
<ul class="fields">
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.name %}
|
||||
{% block fields %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.name %}
|
||||
{% block extra_fields %}{% endblock extra_fields %}
|
||||
{% endblock fields %}
|
||||
<li>
|
||||
{% format_permissions permission_bound_field=form.permissions %}
|
||||
</li>
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
{% csrf_token %}
|
||||
|
||||
<ul class="fields">
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.name %}
|
||||
{% block fields %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.name %}
|
||||
{% block extra_fields %}{% endblock extra_fields %}
|
||||
{% endblock fields %}
|
||||
|
||||
<li>
|
||||
{% format_permissions permission_bound_field=form.permissions %}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import unittest
|
||||
import unittest.mock
|
||||
|
||||
from django import forms
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
|
@ -16,7 +17,9 @@ from wagtail.core.models import Collection, GroupCollectionPermission, GroupPage
|
|||
from wagtail.tests.utils import WagtailTestUtils
|
||||
from wagtail.users.forms import UserCreationForm, UserEditForm
|
||||
from wagtail.users.models import UserProfile
|
||||
from wagtail.users.views.groups import GroupViewSet
|
||||
from wagtail.users.views.users import get_user_creation_form, get_user_edit_form
|
||||
from wagtail.users.wagtail_hooks import get_group_viewset_cls
|
||||
|
||||
|
||||
delete_user_perm_codename = "delete_{0}".format(AUTH_USER_MODEL_NAME.lower())
|
||||
|
@ -37,6 +40,10 @@ class CustomUserEditForm(UserEditForm):
|
|||
attachment = forms.FileField(required=True, label="Attachment")
|
||||
|
||||
|
||||
class CustomGroupViewSet(GroupViewSet):
|
||||
icon = 'custom-icon'
|
||||
|
||||
|
||||
class TestUserFormHelpers(TestCase):
|
||||
|
||||
def test_get_user_edit_form_with_default_form(self):
|
||||
|
@ -1576,3 +1583,33 @@ class TestGroupEditView(TestCase, WagtailTestUtils):
|
|||
# See that the non-registered permission is still there
|
||||
self.assertEqual(self.test_group.permissions.count(), 1)
|
||||
self.assertEqual(self.test_group.permissions.all()[0], self.non_registered_perm)
|
||||
|
||||
|
||||
class TestGroupViewSet(TestCase):
|
||||
def setUp(self):
|
||||
self.app_config = apps.get_app_config('wagtailusers')
|
||||
|
||||
def test_get_group_viewset_cls(self):
|
||||
self.assertIs(get_group_viewset_cls(self.app_config), GroupViewSet)
|
||||
|
||||
def test_get_group_viewset_cls_with_custom_form(self):
|
||||
with unittest.mock.patch.object(
|
||||
self.app_config, 'group_viewset', new='wagtail.users.tests.CustomGroupViewSet'
|
||||
):
|
||||
group_viewset = get_group_viewset_cls(self.app_config)
|
||||
self.assertIs(group_viewset, CustomGroupViewSet)
|
||||
self.assertEqual(group_viewset.icon, 'custom-icon')
|
||||
|
||||
def test_get_group_viewset_cls_custom_form_invalid_value(self):
|
||||
with unittest.mock.patch.object(self.app_config, 'group_viewset', new=12345):
|
||||
with self.assertRaises(ImproperlyConfigured) as exc_info:
|
||||
get_group_viewset_cls(self.app_config)
|
||||
self.assertTrue('refers to a class that is not class path' in str(exc_info.exception))
|
||||
|
||||
def test_get_group_viewset_cls_custom_form_does_not_exist(self):
|
||||
with unittest.mock.patch.object(
|
||||
self.app_config, 'group_viewset', new='wagtail.users.tests.CustomClassDoesNotExist'
|
||||
):
|
||||
with self.assertRaises(ImproperlyConfigured) as exc_info:
|
||||
get_group_viewset_cls(self.app_config)
|
||||
self.assertTrue('refers to a class that is not available' in str(exc_info.exception))
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from django.apps import apps
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models import Q
|
||||
from django.urls import include, path, reverse
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from wagtail.admin.menu import MenuItem
|
||||
|
@ -20,9 +23,32 @@ def register_admin_urls():
|
|||
]
|
||||
|
||||
|
||||
def get_group_viewset_cls(app_config):
|
||||
if app_config.group_viewset is None:
|
||||
group_viewset_cls = GroupViewSet
|
||||
else:
|
||||
if not isinstance(app_config.group_viewset, str):
|
||||
raise ImproperlyConfigured(
|
||||
"'{:s}.group_viewset' refers to a class that is not class path".format(
|
||||
app_config.__class__.__name__
|
||||
)
|
||||
)
|
||||
try:
|
||||
group_viewset_cls = import_string(app_config.group_viewset)
|
||||
except ImportError:
|
||||
raise ImproperlyConfigured(
|
||||
"'{:s}.group_viewset' refers to a class that is not available".format(
|
||||
app_config.__class__.__name__
|
||||
)
|
||||
)
|
||||
return group_viewset_cls
|
||||
|
||||
|
||||
@hooks.register('register_admin_viewset')
|
||||
def register_viewset():
|
||||
return GroupViewSet('wagtailusers_groups', url_prefix='groups')
|
||||
app_config = apps.get_app_config("wagtailusers")
|
||||
group_viewset_cls = get_group_viewset_cls(app_config)
|
||||
return group_viewset_cls('wagtailusers_groups', url_prefix='groups')
|
||||
|
||||
|
||||
# Typically we would check the permission 'auth.change_user' (and 'auth.add_user' /
|
||||
|
|
Ładowanie…
Reference in New Issue