Как получить доступ к данным в шаблоне при использовании DRF ModelViewSet и TemplateHTMLRenderer?

у меня есть фреймворк Django. остальное ModelViewSet и пытаюсь использовать TemplateHTMLRenderer для отображения HTML. Следование в учебник:

from rest_framework import permissions, renderers, viewsets
from rest_framework.decorators import link

from . import models, serializers
from .permissions import IsOwnerOrReadOnly


class SnippetViewSet(viewsets.ModelViewSet):
    template_name = 'snippet-list.html'
    queryset = models.Snippet.objects.all()
    serializer_class = serializers.SnippetSerializer
    renderer_classes = (renderers.TemplateHTMLRenderer,)
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)

    @link(renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def pre_save(self, obj):
        obj.owner = self.request.user

если я добавлю ключ в def resolve_context() Я могу получить доступ к объектам модели в моем шаблоне, которые передаются в RequestContext. Если я не добавлю data ключ тогда я не знаю, как получить доступ к фрагментам.

def resolve_context(self, data, request, response):
    if response.exception:
        data['status_code'] = response.status_code

    #return RequestContext(request, data)  # original source on github
    return RequestContext(request, {'data': data})  # if I add a key I can access it

так что я должен пропустить что-то легкое или как я ожидаю, что это будет вести себя не так как задумали авторы?

4 ответов


Я бы пошел в эту сторону:

class SnippetViewSet(viewsets.ModelViewSet):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    renderer_classes = (renderers.JSONRenderer, renderers.TemplateHTMLRenderer)

    def list(self, request, *args, **kwargs):
        response = super(SnippetViewSet, self).list(request, *args, **kwargs)
        if request.accepted_renderer.format == 'html':
            return Response({'data': response.data}, template_name='home.html')
        return response

и использовать http://127.0.0.1:8000/snippets/.html чтобы получить таблицу (или любой суффикс, который вы используете).

таким образом, вы не переопределяете распознаватель для каждого типа рендеринга.

другим решением было бы просто создать выделенное представление для действия списка и использовать только HTML-визуализатор. Но тогда у вас будет небольшое дублирование кода.


Я также встретил тот же вопрос с вами, и я тоже так думал. Я пришел сюда через Гугл. Мне не понравилось переопределять " Def list (self, request, *args, **kwargs):", потому что я чувствовал, что это сломало идею дизайна viewset. После того, как я исследовал учебник фрагмента и исходный код в "site-packages\rest_framework", я получил ключ, а не набор представлений, но "сериализатор.данные." В ...site-packages\rest_framework\serializers.py", я нашел класс BaseSerializer, то есть верхний базовый класс ModelSerializer. Свой свойство "data" определяется следующим образом:

@property
def data(self):
    ... # omitted the function body here, because it didn't care about this solution.
    return self._data

эти данные свойств являются только "сериализатором".данные " это просто ответ, переданный шаблону. Поэтому я просто переопределил свойство data в "snippets/serializers.py", и после вызова метода отца, установите ключ для возвращаемых данных:

class SnippetSerializer(serializers.ModelSerializer):

    @property
    def data(self):
        return { 'data' : super(serializers.ModelSerializer, self).data } #'data' can be replaced with other wanted name.

    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

OK, используйте имя "данные" в вашем шаблоне.


Я подкласс и переопределил метод, который предоставляет контекст шаблона, так что данные сериализатора доступны в разделе data в контексте шаблона:

from rest_framework.renderers import TemplateHTMLRenderer


class MyHTMLRenderer(TemplateHTMLRenderer):
    def get_template_context(self, data, renderer_context):
        context = {'data': data}
        response = renderer_context['response']
        if response.exception:
            data['status_code'] = response.status_code
        return context

внутри viewset использовать рендерер класс

renderer_classes = (рендереры.JSONRenderer, renderers.TemplateHTMLRenderer)

Как выше и переопределить ListModelMixinметод списка.

mariodev's ответ дает лучший пример также.