Wagtail:序列化页面模型

Posted

技术标签:

【中文标题】Wagtail:序列化页面模型【英文标题】:Wagtail: Serializing page model 【发布时间】:2017-07-21 05:58:45 【问题描述】:

我正在使用 wagtail 作为网站的 REST 后端。该网站是使用 react 构建的,并通过 wagtails API v2 获取数据。

SPA 网站需要能够在 wagtail 中显示页面预览。我的想法是覆盖页面模型上的serve_preview,并简单地将新页面序列化为 JSON 并将其写入我的前端可以访问的缓存。但是我无法将我的页面序列化为 json。所有的尝试都让人觉得很“hackish”

我曾多次尝试使用序列化程序中内置的 wagtails 扩展,但均未成功:

尝试 1:

   def serve_preview(self, request, mode_name):

        from wagtail.api.v2.endpoints import PagesAPIEndpoint

        endpoint = PagesAPIEndpoint()
        setattr(request, 'wagtailapi_router',
                WagtailAPIRouter('wagtailapi_v2'))
        endpoint.request = request
        endpoint.action = None
        endpoint.kwargs = 'slug': self.slug, 'pk': self.pk
        endpoint.lookup_field = 'pk'

        serializer = endpoint.get_serializer(self)

感觉这里用router很丑,设置一堆attrs

尝试 2:

 def serve_preview(self, request, mode_name):
    from wagtail.api.v2.endpoints import PagesAPIEndpoint

    fields = PagesAPIEndpoint.get_available_fields(self)
    if hasattr(self, 'api_fields'):
        fields.extend(self.api_fields)
    serializer_class = get_serializer_class(
        type(self), fields, meta_fields=[PagesAPIEndpoint.meta_fields], base=PageSerializer)
    serializer = serializer_class(self)

更好,但我遇到了上下文问题:

Traceback (most recent call last):
...
File "/usr/local/lib/python3.5/site-packages/wagtail/api/v2/serializers.py", line 92, in to_representation    
self.context['view'].seen_types[name] = page.specific_class
    KeyError: 'view'

有什么困难吗?

【问题讨论】:

【参考方案1】:

可能是一个没有答案的答案,但我在 DRF、Wagtail 在 DRF 之上的分层以及缓存 json 结果的需要方面也遇到了挑战(据我所知,DRF 没有内置缓存,所以这是一个额外的挑战)。在最近的一个项目中,我最终只是在视图中构建了一个字典列表,然后使用HttpResponse() 将它们发送回来,完全绕过了 DRF 和 Wagtail API。代码最终变得简单、易读且易于缓存:

import json
from django.http import HttpResponse
from django.core.cache import cache

data = cache.get('mydata')
if not data:

    datalist = []
    for foo in bar:
        somedata = 
        # Populate somedata, "serializing" fields manually...
        datalist.append(somedata)

# Cache for a week.
data = datalist
cache.set('mydata', datalist, 60 * 60 * 24 * 7)

return HttpResponse(json.dumps(data), content_type='application/json')

不像使用预先构建的 REST 框架那样优雅,但有时​​更简单的方法只是更有效率...

【讨论】:

酷!我想它可以工作,但在这里手动附加不是一个选项。如果您认为合适,请随意尝试下面的方法,总是尽可能地“自动化”。也是一个典型,django 有一个内置的JsonResponse,它和你下面的HttpResponse 做同样的事情【参考方案2】:

通过深入研究源代码解决了它。

首先定义一个空的虚拟视图:

class DummyView(GenericViewSet):

    def __init__(self, *args, **kwargs):
        super(DummyView, self).__init__(*args, **kwargs)

        # seen_types is a mapping of type name strings (format: "app_label.ModelName")
        # to model classes. When an object is serialised in the API, its model
        # is added to this mapping. This is used by the Admin API which appends a
        # summary of the used types to the response.
        self.seen_types = OrderedDict()

然后使用此视图并手动设置序列化程序的上下文。在我的上下文中,我也使用与我的 api 中相同的路由器。它具有由 PageSerializer 调用以解析某些字段的方法。有点奇怪,它与 wagtail api 紧密结合,但至少这是有效的:

def serve_preview(self, request, mode_name):

        import starrepublic.api as StarApi

        fields = StarApi.PagesAPIEndpoint.get_available_fields(self)
        if hasattr(self, 'api_fields'):
            fields.extend(self.api_fields)
        serializer_class = get_serializer_class(
            type(self), fields, meta_fields=[StarApi.PagesAPIEndpoint.meta_fields], base=PageSerializer)
        serializer = serializer_class(
            self, context='request': request, 'view': DummyView(), 'router': StarApi.api_router)

别忘了导入:

from wagtail.api.v2.serializers import get_serializer_class
from rest_framework.viewsets import GenericViewSet
from rest_framework import status
from rest_framework.response import Response
from django.http import JsonResponse
from django.http import HttpResponse

【讨论】:

以上是关于Wagtail:序列化页面模型的主要内容,如果未能解决你的问题,请参考以下文章

剃须刀页面,如何将 json 序列化字符串传递给模型属性

Wagtail 页面中的字段权限

Wagtail ModelAdmin 内联?

在 Wagtail 页面上禁用 CSRF 验证

Wagtail - 在页面上呈现带有相关片段和标签的数据时遇到问题

Wagtail:如何在管理员中设置计算字段(@property)标题