2016-08-29 9 views
0

ViewSetは必要なものすべてを行いますが、テンプレート(TemplateHTMLRenderer)に余分なコンテキストを渡したい場合は、 (list()、create()など)を返すDjango RESTフレームワークビューセットにコンテキストを追加する方法

私が見ることができる唯一の方法は、ビューセットで完全に再定義することですが、簡単な方法があるようです今私のコードは次のように見ているが、私はdifferen追加したいされます

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') 

...メソッドのセット全体を再定義しなくても、テンプレートにコンテキストのビットを追加私はこのような小さな変化のためにメソッド全体を再定義することを避けようとしています。私は原則的に「pleasedontbelong」に反対するが、このように...

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") 
+0

あなたはそれが間違っています、DRF APIにはテンプレートはありません。コンテキストがシリアライザに渡され、シリアライザのデータがレンダリングに送られ、リクエストの「Accept」ヘッダがjson、csv、さらにはHTML – pleasedontbelong

+0

のようにデータをレンダリングする方法を定義するようになります。データを取り込んでDRFを行う方法を処理する必要があります。私は、ビューとフォームなどの別のアプリケーションを使用して、達成したいデータをAPIに送信する必要がありますか? – deltaskelta

+0

チュートリアル全体に従うhttp://www.django-rest-framework.org/tutorial/quickstart/ – pleasedontbelong

答えて

2

は、私が余分なコンテキストデータは、シリアライザから放出されるべきであるという事実に彼に同意します。シリアライザはすべてのレンダラーがレンダリング方法を知っているネイティブのPythonデータ型を返すので、これは最もクリーンな方法です。

相続人はどのようにそれは次のようになります。

ビューセット:

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 

コンテキストにデータを追加するには、ビューセットは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'}をテンプレートに追加する必要があります。

+0

私は 'AdminRenderer'の' render'メソッドによって呼び出されるget_contextをオーバーライドして同様の成功を収めていた 'TemplateHtmlRenderer'の代わりに' AdminRenderer'のサブクラスを使います。 –

1

Django Rest Framework(DRF)3.xでは同じ問題が発生し、やや異なる方法で解決しました。私は、TemplateHTMLRendererクラスの比較的複雑なレンダリングメソッドをオーバーライドする必要はないと信じていますが、はるかに単純なメソッドget_template_context(または以前のバージョンのDRFではresolve_context)だけです。

  1. オーバーライド(すでに示唆したように)あなたのビューセットにget_renderer_context方法:

    def get_renderer_context(self): 
        context = super().get_renderer_context() 
        context['foo'] = 'bar' 
        return context 
    
  2. サブクラスTemplateHTMLRendererは、唯一の代わりにget_template_contextメソッドをオーバーライドし、次のように

    手順がありますレンダーメソッド全体(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に追加されたすべての他の変数がそうであるように。

関連する問題