diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index a09518533e..f67a4ce1d3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -15,6 +15,7 @@ Changelog
* Add informational Codecov status checks for GitHub CI pipelines (Tom Hu)
* Replace `PageRevision` with generic `Revision` model (Sage Abdullah)
* Make it possible to reuse and customise Wagtail’s fonts with CSS variables (LB (Ben) Johnston)
+ * Add better handling and informative developer errors for cross linking URLS (e.g. success after add) in generic views `wagtail.admin.views.generic` (Matt Westcott)
* Fix: Typo in `ResumeWorkflowActionFormatter` message (Stefan Hammer)
* Fix: Throw a meaningful error when saving an image to an unrecognised image format (Christian Franke)
* Fix: Remove extra padding for headers with breadcrumbs on mobile viewport (Steven Steinwand)
diff --git a/docs/releases/4.0.md b/docs/releases/4.0.md
index 95a0fdc0c2..40c201780f 100644
--- a/docs/releases/4.0.md
+++ b/docs/releases/4.0.md
@@ -20,6 +20,7 @@ depth: 1
* Use `FormData` instead of jQuery's `form.serialize` when editing documents or images just added so that additional fields can be better supported (Stefan Hammer)
* Add informational Codecov status checks for GitHub CI pipelines (Tom Hu)
* Make it possible to reuse and customise Wagtail’s fonts with CSS variables (LB (Ben) Johnston)
+ * Add better handling and informative developer errors for cross linking URLS (e.g. success after add) in generic views `wagtail.admin.views.generic` (Matt Westcott)
### Bug fixes
diff --git a/wagtail/admin/templates/wagtailadmin/generic/edit.html b/wagtail/admin/templates/wagtailadmin/generic/edit.html
index de19fc4060..a478732bff 100644
--- a/wagtail/admin/templates/wagtailadmin/generic/edit.html
+++ b/wagtail/admin/templates/wagtailadmin/generic/edit.html
@@ -3,7 +3,7 @@
{% block actions %}
- {% if can_delete %}
+ {% if delete_url %}
{{ delete_item_label }}
{% endif %}
{% endblock %}
diff --git a/wagtail/admin/templates/wagtailadmin/generic/index.html b/wagtail/admin/templates/wagtailadmin/generic/index.html
index 77adf18f4b..ee0ebdccf4 100644
--- a/wagtail/admin/templates/wagtailadmin/generic/index.html
+++ b/wagtail/admin/templates/wagtailadmin/generic/index.html
@@ -4,9 +4,8 @@
{% block titletag %}{{ page_title }} {{ page_subtitle }}{% endblock %}
{% block content %}
- {% if can_add %}
- {% url view.add_url_name as add_link %}
- {% include "wagtailadmin/shared/header.html" with title=page_title subtitle=page_subtitle action_url=add_link action_text=view.add_item_label icon=header_icon only %}
+ {% if add_url %}
+ {% include "wagtailadmin/shared/header.html" with title=page_title subtitle=page_subtitle action_url=add_url action_text=add_item_label icon=header_icon only %}
{% else %}
{% include "wagtailadmin/shared/header.html" with title=page_title subtitle=page_subtitle icon=header_icon only %}
{% endif %}
diff --git a/wagtail/admin/views/generic/models.py b/wagtail/admin/views/generic/models.py
index 92955169d2..bb5711d0d5 100644
--- a/wagtail/admin/views/generic/models.py
+++ b/wagtail/admin/views/generic/models.py
@@ -1,4 +1,5 @@
from django import VERSION as DJANGO_VERSION
+from django.core.exceptions import ImproperlyConfigured
from django.db import transaction
from django.forms import Form
from django.http import HttpResponseRedirect
@@ -62,6 +63,7 @@ class IndexView(
model = None
index_url_name = None
add_url_name = None
+ add_item_label = _("Add")
edit_url_name = None
template_name = "wagtailadmin/generic/index.html"
context_object_name = None
@@ -141,6 +143,10 @@ class IndexView(
if self.edit_url_name:
return reverse(self.edit_url_name, args=(instance.pk,))
+ def get_add_url(self):
+ if self.add_url_name:
+ return reverse(self.add_url_name)
+
def get_valid_orderings(self):
orderings = []
for col in self.columns:
@@ -169,6 +175,10 @@ class IndexView(
self.permission_policy is None
or self.permission_policy.user_has_permission(self.request.user, "add")
)
+ if context["can_add"]:
+ context["add_url"] = self.get_add_url()
+ context["add_item_label"] = self.add_item_label
+
context["table"] = table
context["media"] = table.media
context["index_url"] = index_url
@@ -201,9 +211,19 @@ class CreateView(
submit_button_label = gettext_lazy("Create")
def get_add_url(self):
+ if not self.add_url_name:
+ raise ImproperlyConfigured(
+ "Subclasses of wagtail.admin.views.generic.models.CreateView must provide an "
+ "add_url_name attribute or a get_add_url method"
+ )
return reverse(self.add_url_name)
def get_success_url(self):
+ if not self.index_url_name:
+ raise ImproperlyConfigured(
+ "Subclasses of wagtail.admin.views.generic.models.CreateView must provide an "
+ "index_url_name attribute or a get_success_url method"
+ )
return reverse(self.index_url_name)
def get_success_message(self, instance):
@@ -289,12 +309,23 @@ class EditView(
return str(self.object)
def get_edit_url(self):
+ if not self.edit_url_name:
+ raise ImproperlyConfigured(
+ "Subclasses of wagtail.admin.views.generic.models.EditView must provide an "
+ "edit_url_name attribute or a get_edit_url method"
+ )
return reverse(self.edit_url_name, args=(self.object.id,))
def get_delete_url(self):
- return reverse(self.delete_url_name, args=(self.object.id,))
+ if self.delete_url_name:
+ return reverse(self.delete_url_name, args=(self.object.id,))
def get_success_url(self):
+ if not self.index_url_name:
+ raise ImproperlyConfigured(
+ "Subclasses of wagtail.admin.views.generic.models.EditView must provide an "
+ "index_url_name attribute or a get_success_url method"
+ )
return reverse(self.index_url_name)
def save_instance(self):
@@ -350,12 +381,13 @@ class EditView(
context = super().get_context_data(**kwargs)
context["action_url"] = self.get_edit_url()
context["submit_button_label"] = self.submit_button_label
- context["delete_url"] = self.get_delete_url()
- context["delete_item_label"] = self.delete_item_label
context["can_delete"] = (
self.permission_policy is None
or self.permission_policy.user_has_permission(self.request.user, "delete")
)
+ if context["can_delete"]:
+ context["delete_url"] = self.get_delete_url()
+ context["delete_item_label"] = self.delete_item_label
return context
@@ -381,12 +413,22 @@ class DeleteView(
return super().get_object(queryset)
def get_success_url(self):
+ if not self.index_url_name:
+ raise ImproperlyConfigured(
+ "Subclasses of wagtail.admin.views.generic.models.DeleteView must provide an "
+ "index_url_name attribute or a get_success_url method"
+ )
return reverse(self.index_url_name)
def get_page_subtitle(self):
return str(self.object)
def get_delete_url(self):
+ if not self.index_url_name:
+ raise ImproperlyConfigured(
+ "Subclasses of wagtail.admin.views.generic.models.DeleteView must provide a "
+ "delete_url_name attribute or a get_delete_url method"
+ )
return reverse(self.delete_url_name, args=(self.object.id,))
def get_success_message(self):