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

发布于 2025-01-11 14:45:02 字数 3764 浏览 0 评论 0原文

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

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

我正在尝试遵循文档,但出现以下错误:

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)

I've defined a custom page model (a blog post) as a child of a parent model (a blog index page) and I want to test that the child can be created under its parent.

The BlogPage and BlogIndexPage models are copied from the wagtail "basic blog" example in the documentation, and works as expected.

I'm trying to follow the documentation but I get the following error:

AssertionError: Creating a page failed for an unknown reason

Through trial and error, I know that the error is caused by including an InlinePanel that references another model (BlogPageGalleryImage). If I remove this panel from my BlogPost model definition then the test will pass. I don't understand why including the panel causes an error, or how to solve this problem.

Any help is much appreciated!

The problematic line:

...

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

...

The models:

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"),
    ]

The test:

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

宛菡 2025-01-18 14:45:02

传递给 assertCanCreate 的数据是由“create”视图处理的 HTTP 表单提交数据的字典。当您将 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)

您不需要在表单提交中包含深度,因为这是一个内部数据库字段,用于跟踪页面在页面树中的位置 - 并且已经在assertCanCreate中处理了 调用,因为您已将 root_page 指定为父页面。)

The data passed to assertCanCreate is a dict of HTTP form submission data to be handled by the 'create' view. When you have an InlinePanel as part of the creation form - even if you're not passing any data into it - there's a bundle of extra form fields that needs to be present, to tell it how many child forms are being submitted.

You can use the inline_formset helper (in conjunction with the nested_form_data helper which flattens the nested structure into a plain set of form fields) from Wagtail's testing utilities to construct a compatible form submission:

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)

(You shouldn't need to include depth in the form submission, as that's an internal database field used to keep track of the page's position in the page tree - and that's already taken care of in the assertCanCreate call as you've specified root_page as the parent page.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文