kopia lustrzana https://github.com/wagtail/wagtail
rodzic
b7ab0496f1
commit
5a1ba5abe2
|
@ -25,6 +25,7 @@ Changelog
|
||||||
* Docs: Document `restriction_type` field on PageViewRestriction (Shlomo Markowitz)
|
* Docs: Document `restriction_type` field on PageViewRestriction (Shlomo Markowitz)
|
||||||
* Docs: Document Wagtail's bug bounty policy (Jake Howard)
|
* Docs: Document Wagtail's bug bounty policy (Jake Howard)
|
||||||
* Docs: Fix incorrect Sphinx-style code references to use MyST style (Byron Peebles)
|
* 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: 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: 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)
|
* Maintenance: Exclude the `client/scss` directory in Tailwind content config to speed up CSS compilation (Sage Abdullah)
|
||||||
|
|
|
@ -43,6 +43,7 @@ depth: 1
|
||||||
* Document `restriction_type` field on PageViewRestriction (Shlomo Markowitz)
|
* Document `restriction_type` field on PageViewRestriction (Shlomo Markowitz)
|
||||||
* Document Wagtail's bug bounty policy (Jake Howard)
|
* Document Wagtail's bug bounty policy (Jake Howard)
|
||||||
* Fix incorrect Sphinx-style code references to use MyST style (Byron Peebles)
|
* 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
|
### Maintenance
|
||||||
|
|
|
@ -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.
|
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:
|
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.
|
||||||
|
|
||||||
- It must inherit from {class}`wagtail.models.Orderable`
|
|
||||||
- It must have a `ParentalKey` to the parent model
|
|
||||||
|
|
||||||
````{note}
|
````{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:
|
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:
|
||||||
|
|
|
@ -1563,6 +1563,10 @@ class TestInlinePanelWithTags(WagtailTestUtils, TestCase):
|
||||||
"comments-INITIAL_FORMS": 0,
|
"comments-INITIAL_FORMS": 0,
|
||||||
"comments-MIN_NUM_FORMS": 0,
|
"comments-MIN_NUM_FORMS": 0,
|
||||||
"comments-MAX_NUM_FORMS": 1000,
|
"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(
|
response = self.client.post(
|
||||||
reverse(
|
reverse(
|
||||||
|
@ -1578,6 +1582,49 @@ class TestInlinePanelWithTags(WagtailTestUtils, TestCase):
|
||||||
self.assertEqual(new_page.addresses.first().tags.count(), 2)
|
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):
|
class TestInlinePanelNonFieldErrors(WagtailTestUtils, TestCase):
|
||||||
"""
|
"""
|
||||||
Test that non field errors will render for InlinePanels
|
Test that non field errors will render for InlinePanels
|
||||||
|
|
|
@ -52,6 +52,7 @@ from wagtail.test.testapp.models import (
|
||||||
FormPageWithRedirect,
|
FormPageWithRedirect,
|
||||||
GalleryPage,
|
GalleryPage,
|
||||||
PageChooserModel,
|
PageChooserModel,
|
||||||
|
PersonPage,
|
||||||
RestaurantPage,
|
RestaurantPage,
|
||||||
RestaurantTag,
|
RestaurantTag,
|
||||||
SimplePage,
|
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):
|
class TestInlinePanelGetComparison(TestCase):
|
||||||
fixtures = ["test.json"]
|
fixtures = ["test.json"]
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2097,6 +2097,7 @@ class PersonPage(Page):
|
||||||
"Person",
|
"Person",
|
||||||
),
|
),
|
||||||
InlinePanel("addresses", label="Address"),
|
InlinePanel("addresses", label="Address"),
|
||||||
|
InlinePanel("social_links", label="Social links"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class Meta:
|
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):
|
class RestaurantPage(Page):
|
||||||
tags = ClusterTaggableManager(through="tests.TaggedRestaurant", blank=True)
|
tags = ClusterTaggableManager(through="tests.TaggedRestaurant", blank=True)
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue