簡體   English   中英

Django REST Framework如何向ViewSet添加上下文

[英]Django REST Framework how to add context to a ViewSet

ViewSets可以完成我想要的一切,但是我發現如果我想將額外的上下文傳遞給模板(使用TemplateHTMLRenderer),那么我將不得不使用提供響應的函數。(例如list(),create()等)

我可以看到的唯一方法是在ViewSet中完全重新定義它們,但是似乎應該有一種簡單的方法可以向Template添加一些上下文,而不必重新定義整個方法...

class LanguageViewSet(viewsets.ModelViewSet):
    """Viewset for Language objects, use the proper HTTP methods to modify them"""
    # TODO: add permissions for this view?
    queryset = Language.objects.all()
    serializer_class = LanguageSerializer
    filter_backends = (filters.DjangoFilterBackend, )
    filter_fields = ('name', 'active')

現在,我的代碼看起來像這樣,但是我想在響應中添加不同的上下文,並且我試圖避免為這么小的更改重新定義整個方法。 像這樣...

class LanguageViewSet(viewsets.ModelViewSet):
    """Viewset for Language objects, use the proper HTTP methods to modify them"""
    # TODO: add permissions for this view?
    queryset = Language.objects.all()
    serializer_class = LanguageSerializer
    filter_backends = (filters.DjangoFilterBackend, )
    filter_fields = ('name', 'active')

    def list(self, **kwargs):
        """Redefinition of list"""

        ..blah blah everything that list does
        return Response({"foo": "bar"}, template_name="index.html")

我遇到了相同的問題,並且在Django Rest Framework(DRF)3.x中以稍微不同的方式解決了。 我認為沒有必要重寫TemplateHTMLRenderer類上相對復雜的render方法,而只需覆蓋更簡單的方法get_template_context (或:在早期版本的DRF中為resolve_context )。

步驟如下:

  1. 覆蓋get_renderer_context上的get_renderer_context方法(如已建議的那樣):

     def get_renderer_context(self): context = super().get_renderer_context() context['foo'] = 'bar' return context 
  2. 子類TemplateHTMLRenderer ,但僅覆蓋get_template_context方法而不是整個render方法(render調用self.get_template_context檢索最終上下文以傳遞給模板):

     class ModifiedTemplateHTMLRenderer(TemplateHTMLRenderer): def get_template_context(self, data, renderer_context): """ Override of TemplateHTMLRenderer class method to display extra context in the template, which is otherwise omitted. """ response = renderer_context['response'] if response.exception: data['status_code'] = response.status_code return data else: context = data # pop keys which we do not need in the template keys_to_delete = ['request', 'response', 'args', 'kwargs'] for item in keys_to_delete: renderer_context.pop(item) for key, value in renderer_context.items(): if key not in context: context[key] = value return context 

{{ foo }}現在可以作為模板變量使用-與在get_renderer_context添加的所有其他變量get_renderer_context

盡管我原則上不同意“請不要屬於”,但我同意他應從序列化程序中發出額外的上下文數據這一事實。 這似乎是最干凈的方法,因為序列化程序將返回本機python數據類型,所有渲染器都將知道如何渲染。

如下所示:

ViewSet:

class LanguageViewSet(viewsets.ModelViewSet):

    queryset = Language.objects.all()
    serializer_class = LanguageSerializer
    filter_backends = (filters.DjangoFilterBackend, )
    filter_fields = ('name', 'active')

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['foo'] = 'bar'
        return context

序列化器:

class YourSerializer(serializers.Serializer):
    field = serializers.CharField()

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        # Access self.context here to add contextual data into ret
        ret['foo'] = self.context['foo']
        return ret

現在,foo應該在模板中可用。

如果您不想弄亂序列化程序,則另一種實現方法是創建自定義TemplateHTMLRenderer。

class TemplateHTMLRendererWithContext(TemplateHTMLRenderer):
    def render(self, data, accepted_media_type=None, renderer_context=None):
        # We can't really call super in this case, since we need to modify the inner working a bit
        renderer_context = renderer_context or {}
        view = renderer_context.pop('view')
        request = renderer_context.pop('request')
        response = renderer_context.pop('response')
        view_kwargs = renderer_context.pop('kwargs')
        view_args = renderer_context.pop('args')

        if response.exception:
            template = self.get_exception_template(response)
        else:
            template_names = self.get_template_names(response, view)
            template = self.resolve_template(template_names)

        context = self.resolve_context(data, request, response, render_context)
        return template_render(template, context, request=request)

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

為了將數據添加到上下文中,ViewSet提供了一個get_renderer_context方法。

class LanguageViewSet(viewsets.ModelViewSet):

    queryset = Language.objects.all()
    serializer_class = LanguageSerializer
    filter_backends = (filters.DjangoFilterBackend, )
    filter_fields = ('name', 'active')

    def get_renderer_context(self):
        context = super().get_renderer_context()
        context['foo'] = 'bar'
        return context

{'foo': 'bar'}現在應該在您的模板中可用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM