Documentation: Inline models optional Orderable, tests (#12034)

Fixes #11887
pull/13001/head
Bojan Mihelac 2024-06-12 14:16:50 +02:00 zatwierdzone przez Matt Westcott
rodzic b7ab0496f1
commit 5a1ba5abe2
7 zmienionych plików z 163 dodań i 4 usunięć

Wyświetl plik

@ -25,6 +25,7 @@ Changelog
* Docs: Document `restriction_type` field on PageViewRestriction (Shlomo Markowitz)
* Docs: Document Wagtail's bug bounty policy (Jake Howard)
* Docs: Fix incorrect Sphinx-style code references to use MyST style (Byron Peebles)
* Docs: Document the fact that `Orderable` is not required for inline panels (Bojan Mihelac)
* Maintenance: Use `DjangoJSONEncoder` instead of custom `LazyStringEncoder` to serialize Draftail config (Sage Abdullah)
* Maintenance: Refactor image chooser pagination to check `WAGTAILIMAGES_CHOOSER_PAGE_SIZE` at runtime (Matt Westcott)
* Maintenance: Exclude the `client/scss` directory in Tailwind content config to speed up CSS compilation (Sage Abdullah)

Wyświetl plik

@ -43,6 +43,7 @@ depth: 1
* Document `restriction_type` field on PageViewRestriction (Shlomo Markowitz)
* Document Wagtail's bug bounty policy (Jake Howard)
* Fix incorrect Sphinx-style code references to use MyST style (Byron Peebles)
* Document the fact that `Orderable` is not required for inline panels (Bojan Mihelac)
### Maintenance

Wyświetl plik

@ -333,10 +333,7 @@ class BlogPage(Page):
Wagtail allows the nesting of other models within a page. This is useful for creating repeated fields, such as related links or items to display in a carousel. Inline model content is also versioned with the rest of the page.
Each inline model requires the following:
- It must inherit from {class}`wagtail.models.Orderable`
- It must have a `ParentalKey` to the parent model
An inline model must have a `ParentalKey` pointing to the parent model. It can also inherit from {class}`wagtail.models.Orderable` to allow reordering of items in the admin interface.
````{note}
The model inlining feature is provided by [django-modelcluster](https://github.com/wagtail/django-modelcluster) and the `ParentalKey` field type must be imported from there:

Wyświetl plik

@ -1563,6 +1563,10 @@ class TestInlinePanelWithTags(WagtailTestUtils, TestCase):
"comments-INITIAL_FORMS": 0,
"comments-MIN_NUM_FORMS": 0,
"comments-MAX_NUM_FORMS": 1000,
"social_links-TOTAL_FORMS": 0,
"social_links-INITIAL_FORMS": 0,
"social_links-MIN_NUM_FORMS": 0,
"social_links-MAX_NUM_FORMS": 1000,
}
response = self.client.post(
reverse(
@ -1578,6 +1582,49 @@ class TestInlinePanelWithTags(WagtailTestUtils, TestCase):
self.assertEqual(new_page.addresses.first().tags.count(), 2)
class TestNonOrderableInlinePanel(WagtailTestUtils, TestCase):
# https://github.com/wagtail/wagtail/issues/11887
def setUp(self):
self.root_page = Page.objects.get(id=2)
self.user = self.login()
def test_create(self):
post_data = {
"title": "Mr Benn",
"slug": "mr-benn",
"first_name": "William",
"last_name": "Benn",
"addresses-TOTAL_FORMS": 0,
"addresses-INITIAL_FORMS": 0,
"addresses-MIN_NUM_FORMS": 0,
"addresses-MAX_NUM_FORMS": 1000,
"action-publish": "Publish",
"comments-TOTAL_FORMS": 0,
"comments-INITIAL_FORMS": 0,
"comments-MIN_NUM_FORMS": 0,
"comments-MAX_NUM_FORMS": 1000,
"social_links-TOTAL_FORMS": 1,
"social_links-INITIAL_FORMS": 0,
"social_links-MIN_NUM_FORMS": 0,
"social_links-MAX_NUM_FORMS": 1000,
"social_links-0-url": "https://twitter.com/mrbenn",
"social_links-0-kind": "twitter",
}
response = self.client.post(
reverse(
"wagtailadmin_pages:add",
args=("tests", "personpage", self.root_page.id),
),
post_data,
)
self.assertRedirects(
response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
)
new_page = PersonPage.objects.get(slug="mr-benn")
self.assertEqual(new_page.social_links.count(), 1)
class TestInlinePanelNonFieldErrors(WagtailTestUtils, TestCase):
"""
Test that non field errors will render for InlinePanels

Wyświetl plik

@ -52,6 +52,7 @@ from wagtail.test.testapp.models import (
FormPageWithRedirect,
GalleryPage,
PageChooserModel,
PersonPage,
RestaurantPage,
RestaurantTag,
SimplePage,
@ -1522,6 +1523,42 @@ class TestInlinePanel(WagtailTestUtils, TestCase):
)
class TestNonOrderableInlinePanel(WagtailTestUtils, TestCase):
fixtures = ["test.json"]
def setUp(self):
self.request = get_dummy_request()
user = AnonymousUser() # technically, Anonymous users cannot access the admin
self.request.user = user
def test_render(self):
"""
Check that the inline panel renders the panels set on the model
when no 'panels' parameter is passed in the InlinePanel definition
"""
social_link_object_list = ObjectList(
[
InlinePanel(
"social_links",
label="Social Links",
)
]
).bind_to_model(PersonPage)
PersonPageForm = social_link_object_list.get_form_class()
person_page = PersonPage()
form = PersonPageForm(instance=person_page)
panel = social_link_object_list.get_bound_panel(
instance=person_page, form=form, request=self.request
)
result = panel.render_html()
# rendered panel must not contain hidden fields for ORDER
self.assertNotInHTML(
'id="id_social_links-__prefix__-ORDER"',
result,
)
class TestInlinePanelGetComparison(TestCase):
fixtures = ["test.json"]

Wyświetl plik

@ -0,0 +1,52 @@
# Generated by Django 4.2.13 on 2024-06-12 12:06
from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
import wagtail.search.index
class Migration(migrations.Migration):
dependencies = [
("tests", "0037_testpermissionedgenericsetting_and_more"),
]
operations = [
migrations.CreateModel(
name="SocialLink",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("url", models.URLField()),
(
"kind",
models.CharField(
choices=[("twitter", "Twitter"), ("facebook", "Facebook")],
max_length=30,
),
),
(
"person",
modelcluster.fields.ParentalKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="social_links",
to="tests.personpage",
verbose_name="Person",
),
),
],
options={
"verbose_name": "Social link",
"verbose_name_plural": "Social links",
},
bases=(wagtail.search.index.Indexed, models.Model),
),
]

Wyświetl plik

@ -2097,6 +2097,7 @@ class PersonPage(Page):
"Person",
),
InlinePanel("addresses", label="Address"),
InlinePanel("social_links", label="Social links"),
]
class Meta:
@ -2133,6 +2134,29 @@ class AddressTag(TaggedItemBase):
)
class SocialLink(index.Indexed, ClusterableModel):
url = models.URLField()
kind = models.CharField(
max_length=30,
choices=[
("twitter", "Twitter"),
("facebook", "Facebook"),
],
)
person = ParentalKey(
to="tests.PersonPage", related_name="social_links", verbose_name="Person"
)
panels = [
FieldPanel("url"),
FieldPanel("kind"),
]
class Meta:
verbose_name = "Social link"
verbose_name_plural = "Social links"
class RestaurantPage(Page):
tags = ClusterTaggableManager(through="tests.TaggedRestaurant", blank=True)