从页面 slug 返回所有带有 Wagtail API 的字段

Returning all fields with Wagtail API from page slug

我正在创建一个 VueJS 前端应用程序,它使用 Wagtail CMS 作为后端并通过 Wagtail APIV2 进行连接。我遇到的问题是通过页面 slug 检索页面信息时。此查询不会 return 其他字段,而按页面类型和页面 ID 查询会。

Blog 模型看起来像这样(为了简洁我删掉了一些方法:

class BlogPage(Page):
    intro = RichTextField(blank=True)
    body = StreamField(blocks.CMSStreamBlock(), blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    date = models.DateField("Post date")
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        default='',
        on_delete=models.SET_NULL,
        related_name='author_data',
        null=True,
        blank=True,
        limit_choices_to=limit_author_choices
    )
    feed_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

    class Meta:
        verbose_name = "Blog and Updates Page"

    content_panels = [
        FieldPanel('title', classname="full title"),
        FieldPanel('date'),
        FieldPanel('author'),
        ImageChooserPanel('feed_image'),
        FieldPanel('tags'),
        FieldPanel('intro', classname="full"),
        StreamFieldPanel('body'),
    ]

    api_fields = [
        APIField('feed_img', serializer=ImageRenditionField('width-800', source='feed_image')),
        APIField('intro'),
        APIField('body'),
        APIField('tags'),
        APIField('date'),
        APIField('author')
    ]

如果我查询 http://localhost:8000/api/v2/pages/?type=cms.BlogPage&fields=* 它 returns:

{
    "meta": {
        "total_count": 4
    },
    "items": [
        {
            "id": 8,
            "meta": {
                "type": "cms.BlogPage",
                "detail_url": "http://localhost:8000/api/v2/pages/8/",
                "html_url": "http://localhost:8000/en/blog/first-blog-post/",
                "slug": "first-blog-post",
                "show_in_menus": false,
                "seo_title": "",
                "search_description": "",
                "first_published_at": "2017-10-18T22:54:14.709694Z"
            },
            "title": "First blog post",
            "feed_img": {
                "url": "/media/images/DSC02705.width-800.jpg",
                "width": 800,
                "height": 534
            },
            "intro": "<p>Praesent placerat in eros sit amet gravida. Curabitur nec semper ligula, sit amet egestas sapien. Nullam feugiat non mi vitae egestas. Morbi hendrerit mauris mauris, et tempor eros euismod hendrerit. Integer tempor lacus nulla, eget posuere ex dignissim quis. Donec laoreet tempor suscipit. Etiam ut purus eget turpis commodo aliquam. Donec sed maximus diam, non venenatis arcu. Sed mollis laoreet euismod.</p>",
            "body": [
                {
                    "type": "paragraph",
                    "value": "<p>A bunch more text in here.</p><p>Ut sit amet nisl condimentum, convallis neque eu, fringilla leo. Quisque tincidunt sed quam vel pulvinar. Maecenas vehicula pharetra volutpat. Integer velit mi, scelerisque quis lacus nec, molestie pharetra nisi. Vivamus efficitur magna vel justo lacinia tincidunt. Nam at mi accumsan, sagittis risus sed, iaculis leo. Nullam faucibus lorem a consequat varius. Etiam consectetur metus dui, et maximus turpis volutpat at. Donec vitae blandit nisi. Phasellus commodo vehicula ante vel accumsan. Fusce nec lorem urna. Pellentesque eget dapibus nibh, in ultrices felis. Curabitur felis erat, luctus eu maximus eu, pretium id lorem.</p><p>Nunc consequat, velit non consectetur laoreet, elit nisl finibus diam, id ultrices nunc quam imperdiet mi. Integer vel mi ac quam viverra pellentesque eu eu ante. Cras at est id augue hendrerit pretium ac non sem. Donec quis auctor sem, vel commodo nisi. Mauris ac tincidunt diam. Sed vel erat rhoncus, euismod nisl sit amet, tincidunt arcu. Nam a auctor lorem. Vestibulum in mauris lacus.</p><p>Duis posuere enim odio, vel lacinia nulla condimentum non. Nulla vitae pulvinar neque, sed ultricies est. Nullam fringilla id nibh imperdiet euismod. Pellentesque mauris turpis, tincidunt id commodo in, dictum a tortor. Vestibulum sit amet mollis lacus. Aenean laoreet venenatis orci. Sed nec aliquam ante. Cras congue eu urna eget faucibus. Ut lobortis convallis dictum. Donec aliquet massa sed tortor molestie, ac vestibulum eros imperdiet. Sed eget elit est. Nulla convallis, lorem ac dignissim aliquam, nisi turpis sollicitudin ipsum, vel dictum urna turpis eu orci. Morbi varius massa nisi, nec egestas massa imperdiet tempor. Morbi semper enim non condimentum bibendum. Mauris pulvinar hendrerit tincidunt.</p>",
                    "id": "bebd35d4-a2ad-4b82-baf1-305e817ec55e"
                }
            ],
            "tags": [
                "Tag1",
                "Tag2"
            ],
            "date": "2017-10-18",
            "author": {
                "id": 2,
                "meta": {
                    "type": "users.User"
                }
            }
        },
        {
            "id": 9,
    .....

如果我查询 http://localhost:8000/api/v2/pages/8/ 所有字段都是 returned。 但是,如果我查询 http://localhost:8000/api/v2/pages/?slug=second-blog-post&fields=*

我明白了

{
    "meta": {
        "total_count": 1
    },
    "items": [
        {
            "id": 9,
            "meta": {
                "type": "cms.BlogPage",
                "detail_url": "http://localhost:8000/api/v2/pages/9/",
                "html_url": "http://localhost:8000/en/blog/second-blog-post/",
                "slug": "second-blog-post",
                "show_in_menus": false,
                "seo_title": "",
                "search_description": "",
                "first_published_at": "2017-10-19T00:07:22.887487Z"
            },
            "title": "Second blog post"
        }
    ]
}

如果我查询 http://localhost:8000/api/v2/pages/?slug=second-blog-post&fields=body 我会得到

{
    "message": "unknown fields: body"
}

看来我无法从 slug 查找中检索所有记录字段。这意味着要从 slug 查找中填充页面,我需要: 1.通过slug查找页面 2.记录页面ID 3. 再次调用以按页面 ID 检索字段。

这似乎是一个漫长的过程。我错过了什么吗?

此问题已在 Wagtail Slack 上提出并回答。这是@gasman

的回答

I think the issue is that the 'fetch by slug' mechanism is still ultimately using the API endpoint for fetching a listing of pages rather than a single page, and that one doesn't call specific() on the queryset - which means only the core Page fields are available.

With a bit of re-plumbing you could customise the PagesAPIEndpoint class to call specific() - the Wagtail admin has an internal API that does a similar thing (along with a bunch of other customisations): https://github.com/wagtail/wagtail/blob/master/wagtail/admin/api/endpoints.py

Alternatively, rather than looking up by slug (which is a bit fragile because the same slug could potentially exist under multiple different parents), you could use the new 'find' endpoint added in Wagtail 2.1: http://docs.wagtail.io/en/v2.1/advanced_topics/api/v2/usage.html#finding-pages-by-html-path

Unfortunately, in its current form it will still involve a redundant round-trip to the API because it works on a redirect, but it'll save you a bit of code at least...