Тестирование Django Wagtail - утверждение, что под родительской страницей может быть создана дочерняя страница заданного типа с изображением

Я определил пользовательскую модель страницы (запись блога) как дочернюю модель родительской модели (индексная страница блога) и хочу проверить, что дочерняя модель может быть создана под родительской моделью.

Модели BlogPage и BlogIndexPage скопированы из примера wagtail "basic blog" в documentation, и работают как ожидалось.

Я пытаюсь следовать документации, но получаю следующую ошибку:

AssertionError: Creating a page failed for an unknown reason

Путем проб и ошибок я понял, что ошибка вызвана включением панели InlinePanel, которая ссылается на другую модель (BlogPageGalleryImage). Если я удалю эту панель из определения модели BlogPost, то тест пройдет. Я не понимаю, почему включение панели вызывает ошибку и как решить эту проблему.

Любая помощь будет очень признательна!

Проблемная строка:

...

InlinePanel("gallery_images", label="Gallery images"),

...

Модели:

class BlogIndexPage(Page):
    template = "blog.html"
    intro = models.TextField(blank=True)
    subpage_types = ["cms.BlogPage", "cms.SimpleBlogPage", "cms.BlogTagIndexPage"]

    def get_context(self, request):
        # Update context to include only published posts, ordered by reverse-chron
        context = super().get_context(request)
        blogpages = self.get_children().live().order_by("-first_published_at")
        context["blogpages"] = blogpages
        return context

    content_panels = Page.content_panels + [FieldPanel("intro", classname="full")]


class BlogPage(Page):
    template = "blog-post.html"
    parent_page_types = ["cms.BlogIndexPage"]

    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    categories = ParentalManyToManyField("cms.BlogCategory", blank=True)

    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    search_fields = Page.search_fields + [
        index.SearchField("intro"),
        index.SearchField("body"),
    ]

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel("date"),
                FieldPanel("tags"),
                FieldPanel("categories", widget=forms.CheckboxSelectMultiple),
            ],
            heading="Meta data",
        ),
        FieldPanel("intro"),
        FieldPanel("body"),
        InlinePanel("gallery_images", label="Gallery images"),
    ]


class BlogPageGalleryImage(Orderable):
    page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name="gallery_images")
    image = models.ForeignKey("wagtailimages.Image", on_delete=models.CASCADE, related_name="+")
    caption = models.CharField(blank=True, max_length=250)

    panels = [
        ImageChooserPanel("image"),
        FieldPanel("caption"),
    ]

Тест:

class MyPageTests(WagtailPageTests):
    def setUp(self):
        self.login()

        indexPage = BlogIndexPage(title="Home page", path="blog", pk=1, depth=1)
        indexPage.save()

        page = BlogPage(
            title="a blog post", intro="an intro", path="blog/post", depth=2, date="2022-02-23"
        )
        page.save()

        image = Image(height=1, width=1)
        image.save()

        galleryImage = BlogPageGalleryImage(pk=1, page=page, image=image, caption="foo")
        galleryImage.save()

        category = BlogCategory(name="cat1", pk=1)
        category.save()

    def test_create_blog_post(self):
        root_page = BlogIndexPage.objects.first()

        data = {
            "date": datetime.date(2022, 2, 28),
            "title": "the title",
            "intro": "the intro",
            "depth": 2,
        }

        self.assertCanCreate(root_page, BlogPage, data)

Данные, передаваемые в assertCanCreate, являются диктом данных отправки HTTP-формы, которые должны быть обработаны представлением 'create'. Когда у вас есть InlinePanel как часть формы создания - даже если вы не передаете в нее никаких данных - есть пучок дополнительных полей формы, которые должны присутствовать , чтобы сообщить ей, сколько дочерних форм отправляется.

Вы можете использовать помощник inline_formset (в сочетании с помощником nested_form_data, который сглаживает вложенную структуру в простой набор полей формы) из утилит тестирования Wagtail для построения совместимой формы отправки:

from wagtail.tests.utils.form_data import inline_formset, nested_form_data

class MyPageTests(WagtailPageTests):
    # ...

    def test_create_blog_post(self):
        root_page = BlogIndexPage.objects.first()

        data = nested_form_data({
            "date": datetime.date(2022, 2, 28),
            "title": "the title",
            "intro": "the intro",
            "gallery_images": inline_formset([])
        })

        self.assertCanCreate(root_page, BlogPage, data)

(Вам не нужно включать depth в отправку формы, так как это внутреннее поле базы данных, используемое для отслеживания позиции страницы в дереве страниц - и об этом уже позаботились в вызове assertCanCreate, так как вы указали root_page в качестве родительской страницы)

Вернуться на верх