Unreleased
---
local:
depth: 1
---
FieldPanels can now be marked as read-only with the read_only=True
keyword argument, so that they are displayed in the admin but cannot be edited. This feature was developed by Andy Babic.
As part of Google Season of Docs 2023, we worked with technical writer Damilola Oladele to make improvements to Wagtail’s "Getting started" tutorial. Here are the specific changes made as part of this project:
Thank you to Damilola for his work, and to Google for sponsoring this project.
md5
as not being used for secure purposes, to avoid flagging on FIPS-mode systems (Sean Kelly)parse_query_string
as a QueryDict
to support multiple values (Aman Pandey)MenuItem.name
for all admin menu and submenu items (Justin Koestinger)PagePermissionPolicy
(Sage Abdullah)UserPagePermissionsProxy
and PagePermissionTester
to use PagePermissionPolicy
(Sage Abdullah, Tidiane Dia)AbstractImage.get_renditions()
for efficient generation of multiple renditions (Andy Babic)href="tel:..."
attribute (Sahil Jangra)StreamField
block when only one block type is declared (Sébastien Corbin)parent_page_types
would disallow it (Dan Braghis)UsageView
from EditView
for snippets (Christer Jensen)RichText
objects with the same values compare as equal (NikilTn)gettext_lazy
on generic model views so that language settings are correctly used (Matt Westcott)MultipleChooserPanel
(Matt Westcott)gettext_lazy
works correctly when using verbose_name
on a generic Settings models (Sébastien Corbin)innerHTML
when modifying DOM content (LB (Ben) Johnston)ValueError
when extending PagesAPIViewSet
and setting meta_fields
to an empty list (Henry Harutyunyan, Alex Morega)ModelAdminGroup
(Onno Timmerman)log_action
parameter on RevisionMixin.save_revision
(Christer Jensen)insert_editor_css
in favour of insert_global_admin_css
(Ester Beltrami)specific
on Task and TaskState (Matt Westcott)parent_context
is mutable (Andreas Nüßlein)UserPagePermissionsProxy
(Sage Abdullah)CONTRIBUTORS
file to Markdown (Dan Braghis)insert_editor_css
hook is deprecatedThe insert_editor_css
hook has been deprecated. The insert_global_admin_css
hook has the same functionality, and all uses of insert_editor_css
should be changed to insert_global_admin_css
.
UserPagePermissionsProxy
is deprecatedThe undocumented wagtail.models.UserPagePermissionsProxy
class is deprecated.
If you use the .for_page(page)
method of the class to get a PagePermissionTester
instance, you can replace it with page.permissions_for_user(user)
.
If you use the other methods, they can be replaced via the wagtail.permission_policies.pages.PagePermissionPolicy
class. The following is a list of the PagePermissionPolicy
equivalent of each method:
from wagtail.models import UserPagePermissionsProxy
from wagtail.permission_policies.pages import PagePermissionPolicy
# proxy = UserPagePermissionsProxy(user)
permission_policy = PagePermissionPolicy()
# proxy.revisions_for_moderation()
permission_policy.revisions_for_moderation(user)
# proxy.explorable_pages()
permission_policy.explorable_instances(user)
# proxy.editable_pages()
permission_policy.instances_user_has_permission_for(user, "change")
# proxy.can_edit_pages()
permission_policy.instances_user_has_permission_for(user, "change").exists()
# proxy.publishable_pages()
permission_policy.instances_user_has_permission_for(user, "publish")
# proxy.can_publish_pages()
permission_policy.instances_user_has_permission_for(user, "publish").exists()
# proxy.can_remove_locks()
permission_policy.user_has_permission(user, "unlock")
The UserPagePermissionsProxy
object that is available in page's ActionMenuItem
context as user_page_permissions
(which might be used as part of a register_page_action_menu_item
hook) has been deprecated. In cases where the page object is available (e.g. the page edit view), the PagePermissionTester
object stored as the user_page_permissions_tester
context variable can still be used.
The UserPagePermissionsProxy
object that is available in the template context as user_page_permissions
as a side-effect of the page_permissions
template tag has also been deprecated.
If you use the user_page_permissions
context variable or use the UserPagePermissionsProxy
class directly, make sure to replace it either with the PagePermissionTester
or the PagePermissionPolicy
equivalent.
get_pages_with_direct_explore_permission
, get_explorable_root_page
, and users_with_page_permission
are deprecatedThe undocumented get_pages_with_direct_explore_permission
and get_explorable_root_page
functions in wagtail.admin.navigation
are deprecated. They can be replaced with PagePermissionPolicy().instances_with_direct_explore_permission(user)
and PagePermissionPolicy().explorable_root_instance(user)
, respectively.
The undocumented users_with_page_permission
function in wagtail.admin.auth
is also deprecated. It can be replaced with PagePermissionPolicy().users_with_permission_for_instance(action, page, include_superusers)
.
GroupPagePermission
now uses Django's Permission
modelThe GroupPagePermission
model that is responsible for assigning page permissions to groups now uses Django's Permission
model instead of a custom string. This means that the permission_type
CharField
has been deprecated and replaced with a permission
ForeignKey
to the Permission
model.
In addition to this, "edit" permissions now use the term change
within the code. As a result, GroupPagePermission
s that were previously recorded with permission_type="edit"
are now recorded with a Permission
object that has the codename="change_page"
and a content_type
that points to the Page
model. Any permission checks that are done using PagePermissionPolicy
should also use change
instead of edit
.
If you have any fixtures for the GroupPagePermission
model, you will need to update them to use the new Permission
model. For example, if you have a fixture that looks like this:
{
"pk": 11,
"model": "wagtailcore.grouppagepermission",
"fields": {
"group": ["Event moderators"],
"page": 12,
"permission_type": "edit"
}
}
Update it to use a natural key for the permission
field instead of the permission_type
field:
{
"pk": 11,
"model": "wagtailcore.grouppagepermission",
"fields": {
"group": ["Event moderators"],
"page": 12,
"permission": ["change_page", "wagtailcore", "page"]
}
}
If you have any code that creates GroupPagePermission
objects, you will need to update it to use the Permission
model instead of the permission_type
string. For example, if you have code that looks like this:
from wagtail.core.models import GroupPagePermission
permission = GroupPagePermission(group=group, page=page, permission_type="edit")
permission.save()
Update it to use the Permission
model instead:
from django.contrib.auth.models import Permission
from wagtail.core.models import GroupPagePermission
permission = GroupPagePermission(
group=group,
page=page,
permission=Permission.objects.get(content_type__app_label="wagtailcore", codename="change_page"),
)
permission.save()
During the deprecation period, the permission_type
field will still be available on the GroupPagePermission
model and is used to automatically populate empty permission
field as part of a system check. The permission_type
field will be removed in Wagtail 6.0.
The ordering for "Object permissions" and "Other permissions" now follows a predictable order equivalent do Django's default Model
ordering.
This will be different to the previous ordering which never intentionally implemented.
This default ordering is now ["content_type__app_label", "content_type__model", "codename"]
, which can now be customised [](customising_group_views_permissions_order).
The AdminTagWidget
widget has now been migrated to a Stimulus controller, if using this widget in Python, no changes are needed to adopt the new approach.
If the widget is being instantiated in JavaScript or HTML with the global util window.initTagField
, this undocumented util should be replaced with the new data-*
attributes approach. Additionally, any direct usage of the jQuery widget in JavaScript (e.g. $('#my-element).tagit()
) should be removed.
The global util will be removed in a future release. It is recommended that the documented AdminTagWidget
be used. However, if you need to use the JavaScript approach you can do this with the following example.
Old syntax
<input id="id_tags" type="text" value="popular, technology" hidden />
<script>
window.initTagField('id_tags', 'path/to/url', { autocompleteOnly: true });
</script>
New syntax
<input
id="id_tags"
type="text"
value="popular, technology"
hidden
data-controller="w-tag"
data-w-tag-options-value='{"autocompleteOnly": true}'
data-w-tag-url-value="/path/to/url"
/>
Note: The data-w-tag-options-value
is a JSON object serialised into string. Django's HTML escaping will handle it automatically when you use the AdminTagWidget
, but if you are manually writing the attributes, be sure to use quotation marks correctly.