测试 Django Wagtail - 断言可以在父级下创建具有图像的给定页面类型的子级

Testing Django Wagtail - assert that a child of the given Page type with an image can be created under the parent

我已经将自定义页面模型(博客 post)定义为父模型(博客索引页面)的子模型,我想测试是否可以在其父模型下创建子模型。

BlogPage 和 BlogIndexPage 模型是从 documentation 中的 wagtail“基本博客”示例复制而来的,并且按预期工作。

我正在尝试按照文档进行操作,但出现以下错误:

AssertionError: Creating a page failed for an unknown reason

通过反复试验,我知道错误是由包含引用另一个模型(BlogPageGalleryImage)的InlinePanel引起的。如果我从我的 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 的数据是要由 'create' 视图处理的 HTTP 表单提交数据的字典。当您将 InlinePanel 作为创建表单的一部分时 - 即使您没有向其中传递任何数据 - 也会有 a bundle of extra form fields that needs to be present,告诉它有多少子表单正在提交。

您可以使用 Wagtail 的测试实用程序中的 inline_formset helper (in conjunction with the nested_form_data 助手将嵌套结构展平为一组普通的表单字段)来构建兼容的表单提交:

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 作为父页面。)