wagtail 7.2.1__py3-none-any.whl → 7.3rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wagtail/__init__.py +1 -1
- wagtail/actions/copy_for_translation.py +4 -2
- wagtail/admin/action_menu.py +4 -1
- wagtail/admin/api/actions/convert_alias.py +2 -2
- wagtail/admin/api/actions/copy.py +2 -2
- wagtail/admin/api/actions/copy_for_translation.py +2 -2
- wagtail/admin/api/actions/create_alias.py +2 -2
- wagtail/admin/api/actions/delete.py +1 -1
- wagtail/admin/api/actions/move.py +1 -1
- wagtail/admin/api/actions/publish.py +2 -2
- wagtail/admin/api/actions/revert_to_page_revision.py +2 -2
- wagtail/admin/api/actions/unpublish.py +1 -1
- wagtail/admin/api/filters.py +2 -2
- wagtail/admin/compare.py +22 -0
- wagtail/admin/forms/account.py +52 -1
- wagtail/admin/forms/comments.py +53 -0
- wagtail/admin/forms/models.py +36 -0
- wagtail/admin/forms/pages.py +7 -0
- wagtail/admin/forms/workflows.py +5 -2
- wagtail/admin/icons.py +4 -3
- wagtail/admin/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ar/LC_MESSAGES/django.po +35 -0
- wagtail/admin/locale/en/LC_MESSAGES/django.po +262 -234
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +72 -43
- wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/it/LC_MESSAGES/django.po +566 -6
- wagtail/admin/locale/it/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/it/LC_MESSAGES/djangojs.po +40 -2
- wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/nl/LC_MESSAGES/django.po +2 -2
- wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/sv/LC_MESSAGES/django.po +330 -15
- wagtail/admin/locale/sv/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/sv/LC_MESSAGES/djangojs.po +3 -2
- wagtail/admin/panels/comment_panel.py +1 -51
- wagtail/admin/panels/title_field_panel.py +3 -1
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
- wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
- wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
- wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
- wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
- wagtail/admin/templates/wagtailadmin/base.html +1 -1
- wagtail/admin/templates/wagtailadmin/generic/edit_partials.html +100 -0
- wagtail/admin/templates/wagtailadmin/generic/form.html +26 -5
- wagtail/admin/templates/wagtailadmin/generic/includes/_loaded_revision_inputs.html +3 -0
- wagtail/admin/templates/wagtailadmin/generic/listing_results.html +1 -17
- wagtail/admin/templates/wagtailadmin/pages/create.html +14 -4
- wagtail/admin/templates/wagtailadmin/pages/edit.html +16 -3
- wagtail/admin/templates/wagtailadmin/pages/edit_partials.html +31 -0
- wagtail/admin/templates/wagtailadmin/pages/index_results.html +1 -9
- wagtail/admin/templates/wagtailadmin/shared/autosave/indicator.html +36 -0
- wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/editing_sessions/list.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/editing_sessions/module.html +19 -3
- wagtail/admin/templates/wagtailadmin/shared/headers/_actions.html +5 -0
- wagtail/admin/templates/wagtailadmin/shared/headers/_history_icon_link.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +8 -9
- wagtail/admin/templates/wagtailadmin/shared/listing/filter_partials.html +19 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +3 -3
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/side_panel.html +3 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/privacy.html +18 -6
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +11 -4
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/workflow.html +22 -1
- wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +1 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panels.html +1 -2
- wagtail/admin/templates/wagtailadmin/shared/unsaved_changes_warning.html +20 -20
- wagtail/admin/templates/wagtailadmin/userbar/base.html +2 -0
- wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +1 -1
- wagtail/admin/templatetags/wagtailadmin_tags.py +6 -14
- wagtail/admin/tests/pages/test_create_page.py +298 -1
- wagtail/admin/tests/pages/test_custom_listing.py +48 -2
- wagtail/admin/tests/pages/test_edit_page.py +721 -7
- wagtail/admin/tests/pages/test_explorer_view.py +9 -5
- wagtail/admin/tests/pages/test_page_search.py +15 -0
- wagtail/admin/tests/pages/test_revisions.py +4 -0
- wagtail/admin/tests/test_account_management.py +88 -2
- wagtail/admin/tests/test_collections_views.py +15 -15
- wagtail/admin/tests/test_compare.py +34 -0
- wagtail/admin/tests/test_editing_sessions.py +230 -8
- wagtail/admin/tests/test_forms.py +192 -1
- wagtail/admin/tests/test_icon_sprite.py +22 -2
- wagtail/admin/tests/test_page_chooser.py +13 -13
- wagtail/admin/tests/test_reports_views.py +4 -1
- wagtail/admin/tests/test_userbar.py +69 -5
- wagtail/admin/tests/test_views_generic.py +5 -5
- wagtail/admin/tests/test_workflows.py +14 -12
- wagtail/admin/tests/viewsets/test_model_viewset.py +13 -0
- wagtail/admin/ui/autosave.py +5 -0
- wagtail/admin/ui/editing_sessions.py +3 -0
- wagtail/admin/ui/side_panels.py +19 -20
- wagtail/admin/userbar.py +48 -27
- wagtail/admin/views/bulk_action/dispatcher.py +2 -2
- wagtail/admin/views/chooser.py +6 -6
- wagtail/admin/views/editing_sessions.py +20 -7
- wagtail/admin/views/generic/__init__.py +1 -0
- wagtail/admin/views/generic/chooser.py +5 -5
- wagtail/admin/views/generic/mixins.py +143 -26
- wagtail/admin/views/generic/models.py +157 -27
- wagtail/admin/views/generic/ordering.py +1 -1
- wagtail/admin/views/generic/preview.py +4 -4
- wagtail/admin/views/home.py +3 -1
- wagtail/admin/views/pages/create.py +77 -29
- wagtail/admin/views/pages/edit.py +160 -34
- wagtail/admin/views/pages/preview.py +4 -4
- wagtail/admin/views/pages/revisions.py +3 -0
- wagtail/admin/views/pages/search.py +4 -4
- wagtail/admin/views/pages/usage.py +2 -2
- wagtail/admin/views/tags.py +2 -2
- wagtail/admin/views/workflows.py +73 -54
- wagtail/admin/viewsets/model.py +34 -8
- wagtail/admin/widgets/button.py +11 -4
- wagtail/admin/widgets/chooser.py +6 -4
- wagtail/admin/widgets/slug.py +1 -1
- wagtail/api/v2/filters.py +27 -21
- wagtail/api/v2/pagination.py +4 -4
- wagtail/api/v2/views.py +7 -7
- wagtail/blocks/list_block.py +0 -8
- wagtail/blocks/migrations/migrate_operation.py +8 -1
- wagtail/blocks/stream_block.py +2 -10
- wagtail/blocks/struct_block.py +192 -12
- wagtail/compat.py +2 -2
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/forms/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/forms/locale/it/LC_MESSAGES/django.po +40 -2
- wagtail/contrib/frontend_cache/backends/azure.py +6 -6
- wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
- wagtail/contrib/frontend_cache/utils.py +1 -1
- wagtail/contrib/redirects/forms.py +1 -1
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +14 -14
- wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.po +15 -2
- wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.po +16 -3
- wagtail/contrib/redirects/middleware.py +11 -7
- wagtail/contrib/redirects/models.py +17 -1
- wagtail/contrib/redirects/tests/test_import_admin_views.py +3 -3
- wagtail/contrib/redirects/tests/test_redirects.py +56 -8
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +6 -6
- wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +43 -2
- wagtail/contrib/search_promotions/tests.py +1 -1
- wagtail/contrib/search_promotions/views/settings.py +24 -25
- wagtail/contrib/settings/jinja2tags.py +2 -2
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/contrib/settings/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/it/LC_MESSAGES/django.po +6 -2
- wagtail/contrib/settings/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/sv/LC_MESSAGES/django.po +3 -2
- wagtail/contrib/settings/tests/generic/test_admin.py +118 -2
- wagtail/contrib/settings/tests/site_specific/test_admin.py +78 -15
- wagtail/contrib/settings/tests/site_specific/test_model.py +2 -2
- wagtail/contrib/settings/views.py +7 -0
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/simple_translation/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/simple_translation/locale/it/LC_MESSAGES/django.po +5 -2
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
- wagtail/contrib/styleguide/tests.py +2 -0
- wagtail/contrib/styleguide/views.py +4 -5
- wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.po +5 -1
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.po +5 -2
- wagtail/contrib/typed_table_block/blocks.py +37 -0
- wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
- wagtail/contrib/typed_table_block/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/typed_table_block/locale/sv/LC_MESSAGES/django.po +4 -3
- wagtail/contrib/typed_table_block/tests.py +108 -0
- wagtail/coreutils.py +4 -4
- wagtail/documents/__init__.py +4 -4
- wagtail/documents/locale/en/LC_MESSAGES/django.po +15 -15
- wagtail/documents/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/it/LC_MESSAGES/django.po +32 -2
- wagtail/documents/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/sv/LC_MESSAGES/django.po +32 -4
- wagtail/documents/models.py +1 -1
- wagtail/documents/tests/test_admin_views.py +19 -4
- wagtail/documents/tests/test_search.py +0 -2
- wagtail/documents/tests/test_views.py +6 -4
- wagtail/documents/views/bulk_actions/add_tags.py +1 -1
- wagtail/embeds/finders/facebook.py +3 -3
- wagtail/embeds/finders/instagram.py +3 -3
- wagtail/embeds/finders/oembed.py +7 -2
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/oembed_providers.py +8 -0
- wagtail/embeds/tests/test_embeds.py +35 -0
- wagtail/images/__init__.py +4 -4
- wagtail/images/admin_urls.py +3 -3
- wagtail/images/blocks.py +1 -1
- wagtail/images/formats.py +2 -2
- wagtail/images/image_operations.py +2 -2
- wagtail/images/locale/en/LC_MESSAGES/django.po +44 -40
- wagtail/images/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/it/LC_MESSAGES/django.po +50 -4
- wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/nl/LC_MESSAGES/django.po +3 -3
- wagtail/images/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/sv/LC_MESSAGES/django.po +49 -6
- wagtail/images/models.py +11 -10
- wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
- wagtail/images/templates/wagtailimages/images/url_generator.html +17 -38
- wagtail/images/templates/wagtailimages/images/url_generator_output.html +28 -0
- wagtail/images/templatetags/wagtailimages_tags.py +4 -4
- wagtail/images/tests/test_admin_views.py +432 -59
- wagtail/images/tests/test_image_operations.py +2 -2
- wagtail/images/tests/test_models.py +0 -2
- wagtail/images/views/bulk_actions/add_tags.py +1 -1
- wagtail/images/views/images.py +72 -39
- wagtail/locale/en/LC_MESSAGES/django.po +103 -105
- wagtail/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/it/LC_MESSAGES/django.po +105 -2
- wagtail/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/sv/LC_MESSAGES/django.po +95 -12
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/locales/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/it/LC_MESSAGES/django.po +13 -2
- wagtail/locales/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/sv/LC_MESSAGES/django.po +4 -3
- wagtail/locales/tests.py +5 -5
- wagtail/models/i18n.py +4 -6
- wagtail/models/media.py +18 -0
- wagtail/models/pages.py +65 -11
- wagtail/models/reference_index.py +15 -0
- wagtail/models/revisions.py +40 -12
- wagtail/models/workflows.py +0 -3
- wagtail/permission_policies/base.py +2 -2
- wagtail/permission_policies/collections.py +2 -2
- wagtail/project_template/requirements.txt +2 -2
- wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/signal_handlers.py +1 -0
- wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/sites/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/sites/locale/sv/LC_MESSAGES/django.po +3 -2
- wagtail/sites/tests.py +7 -7
- wagtail/snippets/action_menu.py +2 -1
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +23 -13
- wagtail/snippets/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/sv/LC_MESSAGES/django.po +12 -1
- wagtail/snippets/tests/test_chooser_block.py +197 -0
- wagtail/snippets/tests/test_chooser_panel.py +149 -0
- wagtail/snippets/tests/test_chooser_views.py +375 -0
- wagtail/snippets/tests/test_chooser_widget.py +22 -0
- wagtail/snippets/tests/test_compare_revisions_view.py +167 -0
- wagtail/snippets/tests/test_copy_view.py +38 -0
- wagtail/snippets/tests/test_create_view.py +1159 -0
- wagtail/snippets/tests/test_delete_view.py +225 -0
- wagtail/snippets/tests/test_edit_view.py +2882 -0
- wagtail/snippets/tests/test_history_view.py +182 -0
- wagtail/snippets/tests/test_index_view.py +105 -0
- wagtail/snippets/tests/test_list_view.py +786 -0
- wagtail/snippets/tests/test_locking.py +28 -0
- wagtail/snippets/tests/test_permissions.py +167 -0
- wagtail/snippets/tests/test_preview.py +3 -3
- wagtail/snippets/tests/test_revert_view.py +343 -0
- wagtail/snippets/tests/test_snippet_models.py +112 -0
- wagtail/snippets/tests/test_unpublish_view.py +228 -0
- wagtail/snippets/tests/test_unschedule_view.py +151 -0
- wagtail/snippets/tests/test_viewset.py +38 -5
- wagtail/snippets/views/snippets.py +78 -30
- wagtail/snippets/widgets.py +2 -2
- wagtail/templatetags/wagtailcore_tags.py +2 -2
- wagtail/test/dummy_external_storage.py +1 -1
- wagtail/test/testapp/fixtures/test.json +22 -0
- wagtail/test/testapp/fixtures/test_empty.json +2 -0
- wagtail/test/testapp/fixtures/test_explorable_pages.json +10 -0
- wagtail/test/testapp/fixtures/test_specific.json +9 -0
- wagtail/test/testapp/migrations/0059_nopromotepage.py +25 -0
- wagtail/test/testapp/models.py +7 -0
- wagtail/test/testapp/views.py +5 -0
- wagtail/test/utils/page_tests.py +7 -7
- wagtail/test/utils/wagtail_factories/builder.py +2 -2
- wagtail/tests/streamfield_migrations/test_migrations.py +35 -0
- wagtail/tests/test_blocks.py +321 -61
- wagtail/tests/test_collection_model.py +12 -0
- wagtail/tests/test_page_model.py +190 -1
- wagtail/tests/test_page_privacy.py +5 -0
- wagtail/tests/test_reference_index.py +42 -0
- wagtail/tests/test_revision_model.py +118 -1
- wagtail/tests/test_utils.py +2 -2
- wagtail/users/locale/en/LC_MESSAGES/django.po +14 -14
- wagtail/users/locale/id_ID/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/id_ID/LC_MESSAGES/django.po +6 -2
- wagtail/users/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/it/LC_MESSAGES/django.po +14 -2
- wagtail/users/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/sv/LC_MESSAGES/django.po +48 -17
- wagtail/users/tests/test_admin_views.py +39 -25
- wagtail/users/utils.py +4 -1
- wagtail/users/views/groups.py +19 -5
- wagtail/users/wagtail_hooks.py +1 -1
- wagtail/utils/loading.py +2 -2
- wagtail-7.3rc1.data/data/AGENTS.md +21 -0
- wagtail-7.3rc1.data/data/CHANGELOG.txt +4941 -0
- wagtail-7.3rc1.data/data/CODE_OF_CONDUCT.md +71 -0
- wagtail-7.3rc1.data/data/CONTRIBUTORS.md +999 -0
- wagtail-7.3rc1.data/data/SPONSORS.md +55 -0
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/METADATA +6 -6
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/RECORD +310 -280
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/WHEEL +1 -1
- wagtail/images/static/wagtailimages/js/image-url-generator.js +0 -1
- wagtail/snippets/tests/test_snippets.py +0 -6377
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/licenses/LICENSE +0 -0
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/top_level.txt +0 -0
|
@@ -4,8 +4,9 @@ from urllib.parse import quote
|
|
|
4
4
|
from django.conf import settings
|
|
5
5
|
from django.contrib.auth import get_user_model
|
|
6
6
|
from django.core.exceptions import PermissionDenied
|
|
7
|
+
from django.db import transaction
|
|
7
8
|
from django.db.models import Prefetch, Q
|
|
8
|
-
from django.http import HttpResponse
|
|
9
|
+
from django.http import HttpResponse, JsonResponse
|
|
9
10
|
from django.shortcuts import get_object_or_404, redirect
|
|
10
11
|
from django.urls import reverse
|
|
11
12
|
from django.utils import timezone
|
|
@@ -20,6 +21,7 @@ from wagtail.admin.action_menu import PageActionMenu
|
|
|
20
21
|
from wagtail.admin.mail import send_notification
|
|
21
22
|
from wagtail.admin.models import EditingSession
|
|
22
23
|
from wagtail.admin.telepath import JSContext
|
|
24
|
+
from wagtail.admin.ui.autosave import AutosaveIndicator
|
|
23
25
|
from wagtail.admin.ui.components import MediaContainer
|
|
24
26
|
from wagtail.admin.ui.editing_sessions import EditingSessionsModule
|
|
25
27
|
from wagtail.admin.ui.side_panels import (
|
|
@@ -29,7 +31,7 @@ from wagtail.admin.ui.side_panels import (
|
|
|
29
31
|
PreviewSidePanel,
|
|
30
32
|
)
|
|
31
33
|
from wagtail.admin.utils import get_valid_next_url_from_request
|
|
32
|
-
from wagtail.admin.views.generic import HookResponseMixin
|
|
34
|
+
from wagtail.admin.views.generic import HookResponseMixin, JsonPostResponseMixin
|
|
33
35
|
from wagtail.admin.views.generic.base import WagtailAdminTemplateMixin
|
|
34
36
|
from wagtail.exceptions import PageClassNotFoundError
|
|
35
37
|
from wagtail.locks import BasicLock, ScheduledForPublishLock, WorkflowLock
|
|
@@ -39,13 +41,18 @@ from wagtail.models import (
|
|
|
39
41
|
CommentReply,
|
|
40
42
|
Page,
|
|
41
43
|
PageSubscription,
|
|
44
|
+
Revision,
|
|
42
45
|
WorkflowState,
|
|
43
46
|
get_default_page_content_type,
|
|
44
47
|
)
|
|
45
48
|
from wagtail.utils.timestamps import render_timestamp
|
|
46
49
|
|
|
47
50
|
|
|
48
|
-
class EditView(
|
|
51
|
+
class EditView(
|
|
52
|
+
WagtailAdminTemplateMixin, HookResponseMixin, JsonPostResponseMixin, View
|
|
53
|
+
):
|
|
54
|
+
partials_template_name = "wagtailadmin/pages/edit_partials.html"
|
|
55
|
+
|
|
49
56
|
def get_page_title(self):
|
|
50
57
|
return _("Editing %(page_type)s") % {
|
|
51
58
|
"page_type": self.page_class.get_verbose_name()
|
|
@@ -57,7 +64,8 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
57
64
|
def get_template_names(self):
|
|
58
65
|
if self.page.alias_of_id:
|
|
59
66
|
return ["wagtailadmin/pages/edit_alias.html"]
|
|
60
|
-
|
|
67
|
+
elif self.hydrate_create_view:
|
|
68
|
+
return [self.partials_template_name]
|
|
61
69
|
else:
|
|
62
70
|
return ["wagtailadmin/pages/edit.html"]
|
|
63
71
|
|
|
@@ -370,7 +378,15 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
370
378
|
|
|
371
379
|
response = self.run_hook("before_edit_page", self.request, self.page)
|
|
372
380
|
if response:
|
|
373
|
-
|
|
381
|
+
if self.expects_json_response and not self.response_is_json(response):
|
|
382
|
+
# Hook response is not suitable for a JSON response, so construct our own error response
|
|
383
|
+
return self.json_error_response(
|
|
384
|
+
"blocked_by_hook",
|
|
385
|
+
_("Request to edit %(model_name)s was blocked by hook.")
|
|
386
|
+
% {"model_name": Page._meta.verbose_name},
|
|
387
|
+
)
|
|
388
|
+
else:
|
|
389
|
+
return response
|
|
374
390
|
|
|
375
391
|
self.subscription, created = PageSubscription.objects.get_or_create(
|
|
376
392
|
page=self.page,
|
|
@@ -404,7 +420,10 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
404
420
|
else:
|
|
405
421
|
self.workflow_tasks = []
|
|
406
422
|
|
|
423
|
+
self.has_unsaved_changes = False
|
|
407
424
|
self.errors_debug = None
|
|
425
|
+
self.autosave_interval = getattr(settings, "WAGTAIL_AUTOSAVE_INTERVAL", 500)
|
|
426
|
+
self.autosave_enabled = self.autosave_interval > 0
|
|
408
427
|
|
|
409
428
|
return super().dispatch(request, page_id, **kwargs)
|
|
410
429
|
|
|
@@ -448,8 +467,6 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
448
467
|
parent_page=self.parent,
|
|
449
468
|
for_user=self.request.user,
|
|
450
469
|
)
|
|
451
|
-
self.has_unsaved_changes = False
|
|
452
|
-
self.page_for_status = self.get_page_for_status()
|
|
453
470
|
|
|
454
471
|
return self.render_to_response(self.get_context_data())
|
|
455
472
|
|
|
@@ -475,12 +492,57 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
475
492
|
and self.workflow_state.user_can_cancel(self.request.user)
|
|
476
493
|
)
|
|
477
494
|
|
|
495
|
+
@cached_property
|
|
496
|
+
def hydrate_create_view(self):
|
|
497
|
+
return bool(self.request.GET.get("_w_hydrate_create_view"))
|
|
498
|
+
|
|
499
|
+
@cached_property
|
|
500
|
+
def latest_revision_created_at(self):
|
|
501
|
+
return self.latest_revision and self.latest_revision.created_at.isoformat()
|
|
502
|
+
|
|
503
|
+
@cached_property
|
|
504
|
+
def is_out_of_date(self):
|
|
505
|
+
if not self.latest_revision:
|
|
506
|
+
return False
|
|
507
|
+
|
|
508
|
+
latest_revision_id = str(self.latest_revision.pk)
|
|
509
|
+
|
|
510
|
+
# Two different sessions cannot have the same autosave revision, so if
|
|
511
|
+
# autosave revision is present, it is either the latest or it is not.
|
|
512
|
+
if overwrite_revision_id := self.request.POST.get("overwrite_revision_id"):
|
|
513
|
+
return overwrite_revision_id != latest_revision_id
|
|
514
|
+
|
|
515
|
+
# Client has not made an autosave revision, check the loaded revision.
|
|
516
|
+
if loaded_revision_id := self.request.POST.get("loaded_revision_id"):
|
|
517
|
+
# If the loaded revision is not the latest revision, it is outdated.
|
|
518
|
+
if loaded_revision_id != latest_revision_id:
|
|
519
|
+
return True
|
|
520
|
+
|
|
521
|
+
# It's pointing to the latest revision, but that revision may have
|
|
522
|
+
# been overwritten by another session (via autosave) since the editor
|
|
523
|
+
# loaded it. The created_at is strictly increasing, so assume the
|
|
524
|
+
# loaded revision outdated if it doesn't match the latest created_at.
|
|
525
|
+
return (
|
|
526
|
+
self.request.POST.get("loaded_revision_created_at", "")
|
|
527
|
+
!= self.latest_revision_created_at
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
# Not enough information to deduce, assume it's up to date.
|
|
531
|
+
return False
|
|
532
|
+
|
|
478
533
|
def post(self, request, *args, **kwargs):
|
|
479
534
|
# Don't allow POST requests if the page is an alias
|
|
480
535
|
if self.page.alias_of_id:
|
|
481
536
|
# Return 405 "Method Not Allowed" response
|
|
482
537
|
return HttpResponse(status=405)
|
|
483
538
|
|
|
539
|
+
# For autosave, we only want to save the page if there are no conflicts
|
|
540
|
+
if self.expects_json_response and self.is_out_of_date:
|
|
541
|
+
return self.json_error_response(
|
|
542
|
+
"invalid_revision",
|
|
543
|
+
_("Saving will overwrite a newer version."),
|
|
544
|
+
)
|
|
545
|
+
|
|
484
546
|
self.form = self.form_class(
|
|
485
547
|
self.request.POST,
|
|
486
548
|
self.request.FILES,
|
|
@@ -548,18 +610,43 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
548
610
|
return self.action_method()
|
|
549
611
|
|
|
550
612
|
def save_action(self):
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
613
|
+
try:
|
|
614
|
+
with transaction.atomic():
|
|
615
|
+
self.page = self.form.save(commit=not self.page.live)
|
|
616
|
+
self.subscription.save()
|
|
617
|
+
|
|
618
|
+
overwrite_revision_id = self.request.POST.get("overwrite_revision_id")
|
|
619
|
+
if overwrite_revision_id:
|
|
620
|
+
try:
|
|
621
|
+
overwrite_revision = self.page.revisions.get(
|
|
622
|
+
pk=overwrite_revision_id
|
|
623
|
+
)
|
|
624
|
+
except Revision.DoesNotExist as e:
|
|
625
|
+
raise PermissionDenied(
|
|
626
|
+
"Cannot overwrite a revision that does not exist."
|
|
627
|
+
) from e
|
|
628
|
+
else:
|
|
629
|
+
overwrite_revision = None
|
|
630
|
+
|
|
631
|
+
# Save revision
|
|
632
|
+
revision = self.page.save_revision(
|
|
633
|
+
user=self.request.user,
|
|
634
|
+
log_action=True, # Always log the new revision on edit
|
|
635
|
+
previous_revision=self.previous_revision,
|
|
636
|
+
overwrite_revision=overwrite_revision,
|
|
637
|
+
clean=False,
|
|
638
|
+
)
|
|
639
|
+
except PermissionDenied as e:
|
|
640
|
+
# The revision passed to overwrite_revision was not valid
|
|
641
|
+
if self.expects_json_response:
|
|
642
|
+
return self.json_error_response("invalid_revision", str(e))
|
|
643
|
+
else:
|
|
644
|
+
messages.error(self.request, str(e))
|
|
645
|
+
self.has_unsaved_changes = True
|
|
646
|
+
return self.render_to_response(self.get_context_data())
|
|
561
647
|
|
|
562
|
-
self.
|
|
648
|
+
if not self.expects_json_response:
|
|
649
|
+
self.add_save_confirmation_message()
|
|
563
650
|
|
|
564
651
|
if self.has_content_changes and "comments" in self.form.formsets:
|
|
565
652
|
changes = self.get_commenting_changes()
|
|
@@ -568,10 +655,28 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
568
655
|
|
|
569
656
|
response = self.run_hook("after_edit_page", self.request, self.page)
|
|
570
657
|
if response:
|
|
571
|
-
|
|
658
|
+
if self.expects_json_response and not self.response_is_json(response):
|
|
659
|
+
# Hook response is not suitable for a JSON response, so ignore it and just use
|
|
660
|
+
# the standard one
|
|
661
|
+
pass
|
|
662
|
+
else:
|
|
663
|
+
return response
|
|
572
664
|
|
|
573
665
|
# Just saving - remain on edit page for further edits
|
|
574
|
-
|
|
666
|
+
if self.expects_json_response:
|
|
667
|
+
return JsonResponse(
|
|
668
|
+
{
|
|
669
|
+
"success": True,
|
|
670
|
+
"pk": self.page.pk,
|
|
671
|
+
"revision_id": revision.pk,
|
|
672
|
+
"revision_created_at": revision.created_at.isoformat(),
|
|
673
|
+
"field_updates": dict(self.form.get_field_updates_for_resave()),
|
|
674
|
+
"comments": self.form.serialize_comments(self.request.user),
|
|
675
|
+
"html": self.render_partials(),
|
|
676
|
+
}
|
|
677
|
+
)
|
|
678
|
+
else:
|
|
679
|
+
return self.redirect_and_remain()
|
|
575
680
|
|
|
576
681
|
def publish_action(self):
|
|
577
682
|
self.page = self.form.save(commit=not self.page.live)
|
|
@@ -851,15 +956,26 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
851
956
|
self.request.user
|
|
852
957
|
)
|
|
853
958
|
elif self.locked_for_user:
|
|
854
|
-
|
|
855
|
-
self.
|
|
856
|
-
|
|
959
|
+
if self.expects_json_response:
|
|
960
|
+
return self.json_error_response(
|
|
961
|
+
"locked", _("The page could not be saved as it is locked.")
|
|
962
|
+
)
|
|
963
|
+
else:
|
|
964
|
+
messages.error(
|
|
965
|
+
self.request, _("The page could not be saved as it is locked.")
|
|
966
|
+
)
|
|
857
967
|
else:
|
|
858
|
-
|
|
859
|
-
self.
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
968
|
+
if self.expects_json_response:
|
|
969
|
+
return self.json_error_response(
|
|
970
|
+
"validation_error",
|
|
971
|
+
_("There are validation errors, click save to highlight them."),
|
|
972
|
+
)
|
|
973
|
+
else:
|
|
974
|
+
messages.validation_error(
|
|
975
|
+
self.request,
|
|
976
|
+
_("The page could not be saved due to validation errors."),
|
|
977
|
+
self.form,
|
|
978
|
+
)
|
|
863
979
|
self.errors_debug = repr(self.form.errors) + repr(
|
|
864
980
|
[
|
|
865
981
|
(name, formset.errors)
|
|
@@ -869,8 +985,6 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
869
985
|
)
|
|
870
986
|
self.has_unsaved_changes = True
|
|
871
987
|
|
|
872
|
-
self.page_for_status = self.get_page_for_status()
|
|
873
|
-
|
|
874
988
|
return self.render_to_response(self.get_context_data())
|
|
875
989
|
|
|
876
990
|
def get_preview_url(self):
|
|
@@ -894,14 +1008,19 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
894
1008
|
parent_page=self.page.get_parent(),
|
|
895
1009
|
),
|
|
896
1010
|
]
|
|
897
|
-
if self.page.is_previewable():
|
|
1011
|
+
if not self.expects_json_response and self.page.is_previewable():
|
|
898
1012
|
side_panels.append(
|
|
899
1013
|
PreviewSidePanel(
|
|
900
1014
|
self.page, self.request, preview_url=self.get_preview_url()
|
|
901
1015
|
)
|
|
902
1016
|
)
|
|
903
|
-
|
|
904
|
-
|
|
1017
|
+
if not self.hydrate_create_view:
|
|
1018
|
+
side_panels.append(ChecksSidePanel(self.page, self.request))
|
|
1019
|
+
if (
|
|
1020
|
+
not self.expects_json_response
|
|
1021
|
+
and not self.hydrate_create_view
|
|
1022
|
+
and self.form.show_comments_toggle
|
|
1023
|
+
):
|
|
905
1024
|
side_panels.append(CommentsSidePanel(self.page, self.request))
|
|
906
1025
|
return MediaContainer(side_panels)
|
|
907
1026
|
|
|
@@ -926,6 +1045,7 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
926
1045
|
),
|
|
927
1046
|
[],
|
|
928
1047
|
self.page.latest_revision_id,
|
|
1048
|
+
self.latest_revision_created_at,
|
|
929
1049
|
)
|
|
930
1050
|
|
|
931
1051
|
def get_action_menu(self):
|
|
@@ -956,7 +1076,7 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
956
1076
|
context.update(
|
|
957
1077
|
{
|
|
958
1078
|
"page": self.page,
|
|
959
|
-
"page_for_status": self.
|
|
1079
|
+
"page_for_status": self.get_page_for_status(),
|
|
960
1080
|
"content_type": self.page_content_type,
|
|
961
1081
|
"edit_handler": bound_panel,
|
|
962
1082
|
"edit_handler_data": edit_handler_data,
|
|
@@ -985,7 +1105,13 @@ class EditView(WagtailAdminTemplateMixin, HookResponseMixin, View):
|
|
|
985
1105
|
and user_perms.can_unlock(),
|
|
986
1106
|
"locale": self.locale,
|
|
987
1107
|
"media": media,
|
|
1108
|
+
"autosave_enabled": self.autosave_enabled,
|
|
1109
|
+
"autosave_interval": self.autosave_interval,
|
|
1110
|
+
"autosave_indicator": AutosaveIndicator(),
|
|
988
1111
|
"editing_sessions": self.get_editing_sessions(),
|
|
1112
|
+
"loaded_revision_created_at": self.latest_revision_created_at,
|
|
1113
|
+
"is_partial": self.expects_json_response or self.hydrate_create_view,
|
|
1114
|
+
"hydrate_create_view": self.hydrate_create_view,
|
|
989
1115
|
}
|
|
990
1116
|
)
|
|
991
1117
|
|
|
@@ -18,8 +18,8 @@ def view_draft(request, page_id):
|
|
|
18
18
|
|
|
19
19
|
try:
|
|
20
20
|
preview_mode = request.GET.get("mode", page.default_preview_mode)
|
|
21
|
-
except IndexError:
|
|
22
|
-
raise PermissionDenied
|
|
21
|
+
except IndexError as e:
|
|
22
|
+
raise PermissionDenied from e
|
|
23
23
|
|
|
24
24
|
return page.make_preview_request(request, preview_mode)
|
|
25
25
|
|
|
@@ -82,8 +82,8 @@ class PreviewOnCreate(PreviewOnEdit):
|
|
|
82
82
|
content_type = ContentType.objects.get_by_natural_key(
|
|
83
83
|
content_type_app_name, content_type_model_name
|
|
84
84
|
)
|
|
85
|
-
except ContentType.DoesNotExist:
|
|
86
|
-
raise Http404
|
|
85
|
+
except ContentType.DoesNotExist as e:
|
|
86
|
+
raise Http404 from e
|
|
87
87
|
|
|
88
88
|
page = content_type.model_class()()
|
|
89
89
|
parent_page = get_object_or_404(Page, id=parent_page_id).specific
|
|
@@ -72,6 +72,9 @@ class RevisionsRevertView(EditView):
|
|
|
72
72
|
def get_context_data(self, **kwargs):
|
|
73
73
|
context = super().get_context_data(**kwargs)
|
|
74
74
|
context["action_url"] = self.get_revisions_revert_url()
|
|
75
|
+
# Autosave does not make much sense in this view, we want the user to
|
|
76
|
+
# explicitly confirm they want to revert to the previous revision
|
|
77
|
+
context["autosave_enabled"] = False
|
|
75
78
|
return context
|
|
76
79
|
|
|
77
80
|
|
|
@@ -91,15 +91,15 @@ class SearchView(PageListingMixin, PermissionCheckedMixin, BaseListingView):
|
|
|
91
91
|
if "content_type" in request.GET:
|
|
92
92
|
try:
|
|
93
93
|
app_label, model_name = request.GET["content_type"].split(".")
|
|
94
|
-
except ValueError:
|
|
95
|
-
raise Http404
|
|
94
|
+
except ValueError as e:
|
|
95
|
+
raise Http404 from e
|
|
96
96
|
|
|
97
97
|
try:
|
|
98
98
|
self.selected_content_type = ContentType.objects.get_by_natural_key(
|
|
99
99
|
app_label, model_name
|
|
100
100
|
)
|
|
101
|
-
except ContentType.DoesNotExist:
|
|
102
|
-
raise Http404
|
|
101
|
+
except ContentType.DoesNotExist as e:
|
|
102
|
+
raise Http404 from e
|
|
103
103
|
|
|
104
104
|
else:
|
|
105
105
|
self.selected_content_type = None
|
|
@@ -46,8 +46,8 @@ class ContentTypeUseView(PageListingMixin, PermissionCheckedMixin, BaseListingVi
|
|
|
46
46
|
content_type = ContentType.objects.get_by_natural_key(
|
|
47
47
|
content_type_app_name, content_type_model_name
|
|
48
48
|
)
|
|
49
|
-
except ContentType.DoesNotExist:
|
|
50
|
-
raise Http404
|
|
49
|
+
except ContentType.DoesNotExist as e:
|
|
50
|
+
raise Http404 from e
|
|
51
51
|
|
|
52
52
|
self.page_class = content_type.model_class()
|
|
53
53
|
|
wagtail/admin/views/tags.py
CHANGED
|
@@ -9,8 +9,8 @@ def autocomplete(request, app_name=None, model_name=None):
|
|
|
9
9
|
if app_name and model_name:
|
|
10
10
|
try:
|
|
11
11
|
content_type = ContentType.objects.get_by_natural_key(app_name, model_name)
|
|
12
|
-
except ContentType.DoesNotExist:
|
|
13
|
-
raise Http404
|
|
12
|
+
except ContentType.DoesNotExist as e:
|
|
13
|
+
raise Http404 from e
|
|
14
14
|
|
|
15
15
|
tag_model = content_type.model_class()
|
|
16
16
|
if not issubclass(tag_model, TagBase):
|
wagtail/admin/views/workflows.py
CHANGED
|
@@ -184,6 +184,12 @@ class Create(CreateView):
|
|
|
184
184
|
def get_form_class(self):
|
|
185
185
|
return self.get_edit_handler().get_form_class()
|
|
186
186
|
|
|
187
|
+
def get_initial_form_instance(self):
|
|
188
|
+
# defining this method ensures that self.object is set to a new instance
|
|
189
|
+
# while constructing the form, making it available to get_pages_formset
|
|
190
|
+
# and get_content_type_form during is_valid
|
|
191
|
+
return self.model()
|
|
192
|
+
|
|
187
193
|
def get_pages_formset(self):
|
|
188
194
|
if self.request.method == "POST":
|
|
189
195
|
return WorkflowPagesFormSet(
|
|
@@ -213,36 +219,41 @@ class Create(CreateView):
|
|
|
213
219
|
context["media"] = form.media + bound_panel.media + pages_formset.media
|
|
214
220
|
return context
|
|
215
221
|
|
|
222
|
+
def is_valid(self, form):
|
|
223
|
+
if not super().is_valid(form):
|
|
224
|
+
return False
|
|
225
|
+
|
|
226
|
+
self.pages_formset = self.get_pages_formset()
|
|
227
|
+
self.content_type_form = self.get_content_type_form()
|
|
228
|
+
|
|
229
|
+
if not self.pages_formset.is_valid() or not self.content_type_form.is_valid():
|
|
230
|
+
self.produced_error_message = self.get_error_message()
|
|
231
|
+
return False
|
|
232
|
+
|
|
233
|
+
return True
|
|
234
|
+
|
|
216
235
|
def form_valid(self, form):
|
|
217
236
|
self.form = form
|
|
218
237
|
|
|
219
238
|
with transaction.atomic():
|
|
220
239
|
self.object = self.save_instance()
|
|
221
240
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
],
|
|
239
|
-
)
|
|
240
|
-
return redirect(self.get_success_url())
|
|
241
|
-
|
|
242
|
-
else:
|
|
243
|
-
transaction.set_rollback(True)
|
|
244
|
-
|
|
245
|
-
return self.form_invalid(form)
|
|
241
|
+
self.pages_formset.save()
|
|
242
|
+
self.content_type_form.save()
|
|
243
|
+
|
|
244
|
+
success_message = self.get_success_message(self.object)
|
|
245
|
+
if success_message is not None:
|
|
246
|
+
messages.success(
|
|
247
|
+
self.request,
|
|
248
|
+
success_message,
|
|
249
|
+
buttons=[
|
|
250
|
+
messages.button(
|
|
251
|
+
reverse(self.edit_url_name, args=(self.object.id,)),
|
|
252
|
+
_("Edit"),
|
|
253
|
+
)
|
|
254
|
+
],
|
|
255
|
+
)
|
|
256
|
+
return redirect(self.get_success_url())
|
|
246
257
|
|
|
247
258
|
|
|
248
259
|
class Edit(EditView):
|
|
@@ -326,42 +337,50 @@ class Edit(EditView):
|
|
|
326
337
|
def get_enable_url(self):
|
|
327
338
|
return reverse(self.enable_url_name, args=(self.object.pk,))
|
|
328
339
|
|
|
340
|
+
def is_valid(self, form):
|
|
341
|
+
if not super().is_valid(form):
|
|
342
|
+
return False
|
|
343
|
+
|
|
344
|
+
if self.object.active:
|
|
345
|
+
# Note: These are hidden when the workflow is inactive
|
|
346
|
+
self.pages_formset = self.get_pages_formset()
|
|
347
|
+
self.content_type_form = self.get_content_type_form()
|
|
348
|
+
|
|
349
|
+
if (
|
|
350
|
+
not self.pages_formset.is_valid()
|
|
351
|
+
or not self.content_type_form.is_valid()
|
|
352
|
+
):
|
|
353
|
+
self.produced_error_message = self.get_error_message()
|
|
354
|
+
return False
|
|
355
|
+
|
|
356
|
+
return True
|
|
357
|
+
|
|
329
358
|
@transaction.atomic()
|
|
330
359
|
def form_valid(self, form):
|
|
331
360
|
self.form = form
|
|
332
361
|
|
|
333
362
|
with transaction.atomic():
|
|
334
363
|
self.object = self.save_instance()
|
|
335
|
-
successful = True
|
|
336
364
|
|
|
337
|
-
# Save pages formset and content type form
|
|
338
|
-
# Note: These are hidden when the workflow is inactive
|
|
339
365
|
if self.object.active:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
_("Edit"),
|
|
359
|
-
)
|
|
360
|
-
],
|
|
361
|
-
)
|
|
362
|
-
return redirect(self.get_success_url())
|
|
363
|
-
|
|
364
|
-
return self.form_invalid(form)
|
|
366
|
+
# Save pages formset and content type form
|
|
367
|
+
# Note: These are hidden when the workflow is inactive
|
|
368
|
+
self.pages_formset.save()
|
|
369
|
+
self.content_type_form.save()
|
|
370
|
+
|
|
371
|
+
success_message = self.get_success_message()
|
|
372
|
+
if success_message is not None:
|
|
373
|
+
messages.success(
|
|
374
|
+
self.request,
|
|
375
|
+
success_message,
|
|
376
|
+
buttons=[
|
|
377
|
+
messages.button(
|
|
378
|
+
reverse(self.edit_url_name, args=(self.object.id,)),
|
|
379
|
+
_("Edit"),
|
|
380
|
+
)
|
|
381
|
+
],
|
|
382
|
+
)
|
|
383
|
+
return redirect(self.get_success_url())
|
|
365
384
|
|
|
366
385
|
|
|
367
386
|
class Disable(DeleteView):
|
|
@@ -651,8 +670,8 @@ class CreateTask(CreateView):
|
|
|
651
670
|
content_type = ContentType.objects.get_by_natural_key(
|
|
652
671
|
self.kwargs["app_label"], self.kwargs["model_name"]
|
|
653
672
|
)
|
|
654
|
-
except (ContentType.DoesNotExist, AttributeError):
|
|
655
|
-
raise Http404
|
|
673
|
+
except (ContentType.DoesNotExist, AttributeError) as e:
|
|
674
|
+
raise Http404 from e
|
|
656
675
|
|
|
657
676
|
# Get class
|
|
658
677
|
model = content_type.model_class()
|
wagtail/admin/viewsets/model.py
CHANGED
|
@@ -2,8 +2,10 @@ from django.contrib.auth import get_permission_codename
|
|
|
2
2
|
from django.contrib.auth.models import Permission
|
|
3
3
|
from django.contrib.contenttypes.models import ContentType
|
|
4
4
|
from django.core.exceptions import ImproperlyConfigured
|
|
5
|
+
from django.db import models
|
|
5
6
|
from django.forms.models import modelform_factory
|
|
6
7
|
from django.urls import path
|
|
8
|
+
from django.urls.converters import get_converters
|
|
7
9
|
from django.utils.functional import cached_property
|
|
8
10
|
from django.utils.text import capfirst
|
|
9
11
|
|
|
@@ -129,6 +131,24 @@ class ModelViewSet(ViewSet):
|
|
|
129
131
|
def permission_policy(self):
|
|
130
132
|
return ModelPermissionPolicy(self.model)
|
|
131
133
|
|
|
134
|
+
@cached_property
|
|
135
|
+
def pk_path_converter(self):
|
|
136
|
+
"""
|
|
137
|
+
:ref:`Path converter <topics/http/urls:path converters>` to use for
|
|
138
|
+
the model's primary key in URL patterns. Defaults to ``"int"`` for
|
|
139
|
+
``IntegerField``, ``"uuid"`` for ``UUIDField``, and ``"str"`` for all
|
|
140
|
+
other types.
|
|
141
|
+
|
|
142
|
+
.. versionadded:: 7.3
|
|
143
|
+
The ``pk_path_converter`` property was added.
|
|
144
|
+
"""
|
|
145
|
+
if isinstance(self.model_opts.pk, models.UUIDField):
|
|
146
|
+
return "uuid"
|
|
147
|
+
if isinstance(self.model_opts.pk, models.IntegerField):
|
|
148
|
+
return "int"
|
|
149
|
+
# Default to string if unknown
|
|
150
|
+
return "str"
|
|
151
|
+
|
|
132
152
|
@cached_property
|
|
133
153
|
def name(self):
|
|
134
154
|
"""
|
|
@@ -649,38 +669,44 @@ class ModelViewSet(ViewSet):
|
|
|
649
669
|
hooks.register("register_permissions", self.get_permissions_to_register)
|
|
650
670
|
|
|
651
671
|
def get_urlpatterns(self):
|
|
672
|
+
conv = self.pk_path_converter
|
|
652
673
|
urlpatterns = [
|
|
653
674
|
path("", self.index_view, name="index"),
|
|
654
675
|
path("results/", self.index_results_view, name="index_results"),
|
|
655
676
|
path("new/", self.add_view, name="add"),
|
|
656
|
-
path("edit/<
|
|
657
|
-
path("delete/<
|
|
658
|
-
path("history/<
|
|
677
|
+
path(f"edit/<{conv}:pk>/", self.edit_view, name="edit"),
|
|
678
|
+
path(f"delete/<{conv}:pk>/", self.delete_view, name="delete"),
|
|
679
|
+
path(f"history/<{conv}:pk>/", self.history_view, name="history"),
|
|
659
680
|
path(
|
|
660
|
-
"history-results/<
|
|
681
|
+
f"history-results/<{conv}:pk>/",
|
|
661
682
|
self.history_results_view,
|
|
662
683
|
name="history_results",
|
|
663
684
|
),
|
|
664
|
-
path("usage/<
|
|
685
|
+
path(f"usage/<{conv}:pk>/", self.usage_view, name="usage"),
|
|
665
686
|
]
|
|
666
687
|
|
|
667
688
|
if self.reorder_view_enabled:
|
|
668
689
|
urlpatterns.append(
|
|
669
|
-
path("reorder/<
|
|
690
|
+
path(f"reorder/<{conv}:pk>/", self.reorder_view, name="reorder")
|
|
670
691
|
)
|
|
671
692
|
|
|
672
693
|
if self.inspect_view_enabled:
|
|
673
694
|
urlpatterns.append(
|
|
674
|
-
path("inspect/<
|
|
695
|
+
path(f"inspect/<{conv}:pk>/", self.inspect_view, name="inspect")
|
|
675
696
|
)
|
|
676
697
|
|
|
677
698
|
if self.copy_view_enabled:
|
|
678
|
-
urlpatterns.append(path("copy/<
|
|
699
|
+
urlpatterns.append(path(f"copy/<{conv}:pk>/", self.copy_view, name="copy"))
|
|
679
700
|
|
|
680
701
|
return urlpatterns
|
|
681
702
|
|
|
682
703
|
def on_register(self):
|
|
683
704
|
super().on_register()
|
|
705
|
+
if self.pk_path_converter not in get_converters():
|
|
706
|
+
raise ImproperlyConfigured(
|
|
707
|
+
f"{self.__class__.__name__}.pk_path_converter is not a "
|
|
708
|
+
"registered path converter"
|
|
709
|
+
)
|
|
684
710
|
self.register_admin_url_finder()
|
|
685
711
|
self.register_reference_index()
|
|
686
712
|
self.register_permissions()
|