Трясогузка: Сериализация модели страницы

Я использую трясогузку в качестве бэкэнда REST для веб-сайта. Веб-сайт построен с использованием реакции и извлекает данные через API трясогузки v2.

Веб-сайт SPA должен иметь возможность показывать превью страниц в трясогузке. Моя мысль состояла в том, чтобы переопределить serve_preview в модели страницы и просто серализовать новую страницу как JSON и записать ее в кеш, к которому может получить доступ мой интерфейс. Но у меня проблемы с сериализацией моей страницы в json. Все предпринятые попытки кажутся очень "хакерскими"

Я сделал несколько попыток, используя расширения трясогузок, встроенные в сериализаторы, но безуспешно:

Попытка 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)

Очень некрасиво использовать здесь маршрутизатор и устанавливать кучу атрибутов.

Попытка 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'

Какие-нибудь хитрости?


person Richard    schedule 01.03.2017    source источник


Ответы (2)


Возможно, ответ без ответа, но у меня тоже были проблемы в области DRF, наслоения трясогузки поверх 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, но иногда более простой подход просто более продуктивен...

person shacker    schedule 02.03.2017
comment
Прохладный! Я думаю, это работает, но добавление вручную здесь не вариант. Не стесняйтесь попробовать мой подход ниже, если вы считаете нужным, всегда приятно автоматизировать как можно больше. Также тип, django имеет встроенный JsonResponse, который делает то же самое, что и ваш HttpResponse ниже - person Richard; 03.03.2017

Решил это, погрузившись в исходный код.

Сначала определите пустой фиктивный вид:

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 для разрешения некоторых полей. Немного странно, что он так тесно связан с 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
person Richard    schedule 03.03.2017