wagtail: Inconsistent use of model verbose_name in permissions UI
Issue Summary
The object permissions UI doesn’t show a model’s verbose_name if it differs from the model’s name when it was created.
Steps to Reproduce
Start a new project with wagtail start myproject and create a simple model like the following:
from django.db import models
from wagtail.snippets.models import register_snippet
@register_snippet
class MyModel(models.Model):
text = models.TextField()
In the group edit view, permissions render like this; note “My model” and “Can view”:
Now, give the model a different verbose_name:
@register_snippet
class MyModel(models.Model):
text = models.TextField()
class Meta:
verbose_name = "Something else"
Now, the permissions render in a surprising way; note “Something else” and “Can view my model”:
As a user, I would expect to see “Can view” the way all other objects are typically listed.
This behavior seems to come from this line that defines the permission “name”:
This code assumes that a model’s content type’s name (perm.content_type.name) will exactly match the name on the permission object (perm.name). This is true as long as the model’s verbose name hasn’t been changed, but, per the docs, content_type.name “is taken from the verbose_name attribute of the model”. So if a model’s verbose name is changed, that change will show up when you look at its content type.
The issue is that when a model is first created, its automatically-generated permissions are given names that contain the model’s name at that time. For example, the above MyModel class generated permissions like this:
110|28|add_mymodel|Can add my model
111|28|change_mymodel|Can change my model
112|28|delete_mymodel|Can delete my model
113|28|view_mymodel|Can view my model
In the above example, the code assumes that since the content type reports its name as Something else, the permission’s name will be Can view something else, but this isn’t a valid assumption. The permission’s name is still what it was when it was created, Can view my model.
To fix this, the code could lookup the model objects corresponding to the permission content types and use those to do the substitution, maybe something like this:
diff --git a/wagtail/users/templatetags/wagtailusers_tags.py b/wagtail/users/templatetags/wagtailusers_tags.py
index c188425ad0..3da81fe0dd 100644
--- a/wagtail/users/templatetags/wagtailusers_tags.py
+++ b/wagtail/users/templatetags/wagtailusers_tags.py
@@ -95,11 +95,15 @@ def format_permissions(permission_bound_field):
}
else:
extra_perms_exist["custom"] = True
+ perm_model_class = perm.content_type.model_class()
custom_perms.append(
{
"perm": perm,
"name": re.sub(
- f"{perm.content_type.name}$", "", perm.name, flags=re.I
+ f"{perm_model_class._meta.model_name}$", "", perm.name, flags=re.I
).strip(),
"selected": checkbox.data["selected"],
}
Technical details
- I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: yes
- Python version: 3.11.1
- Django version: 4.0.10
- Wagtail version: 5.2a0
About this issue
- Original URL
- State: closed
- Created 9 months ago
- Comments: 22 (22 by maintainers)
Commits related to this issue
- Solve #10982 issue and add a test for it — committed to FatGuyy/wagtail by FatGuyy 8 months ago
- Fix inconsistent use of model verbose_name in permissions UI - Fixes #10982 - Rework of #11203 - Modify the sanitized `permission_action` name - Relates to work around for the known Django issue http... — committed to NXPY123/wagtail by NXPY123 5 months ago
- Fix inconsistent use of model verbose_name in permissions UI - Fixes #10982 - Rework of #11203 - Modify the sanitized `permission_action` name - Relates to work around for the known Django issue http... — committed to wagtail/wagtail by NXPY123 5 months ago
@thibaudcolas I’ll give the solution of @chosak a go.
I think this is a Django bug rather than a Wagtail bug: https://code.djangoproject.com/ticket/26756
Edit: never mind. Yes, the root cause is the Django bug, but since we added special handling for it, we should adapt that handling accordingly.