Django REST Framework如何将上下文添加到ViewSet中 [英] Django REST Framework how to add context to a ViewSet

查看:211
本文介绍了Django REST Framework如何将上下文添加到ViewSet中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ViewSets可以执行我想要的一切,但是我发现如果我想通过额外的上下文传递给模板(使用TemplateHTMLRenderer),那么我必须得到给出响应的函数..(像list() create(),etc)



我可以看到的唯一方法是在ViewSet中完全重新定义它们,但似乎应该有一个简单的方法添加一些上下文到模板,而不必重新定义一整套方法...

  class LanguageViewSet(viewsets) ModelViewSet):
语言对象的视图,使用适当的HTTP方法来修改它们
#TODO:为此视图添加权限?
queryset = Language.objects.all()
serializer_class = LanguageSerializer
filter_backends =(filters.DjangoFilterBackend)
filter_fields =('name','active')

现在我的代码看起来像这样,但我会想要添加不同的上下文的回复,我正在尝试以避免重新定义整个方法进行这样一个小的改变。这样...

  class LanguageViewSet(viewsets.ModelViewSet):
语言对象的视图,使用适当的HTTP方法修改它们
#TODO:为此视图添加权限?
queryset = Language.objects.all()
serializer_class = LanguageSerializer
filter_backends =(filters.DjangoFilterBackend)
filter_fields =('name','active')

def list(self,** kwargs):
重新定义列表

..blah blah列表中的所有内容
返回响应({foo:bar},template_name =index.html)


解决方案

虽然我原则上不同意喜悦,但我同意他的观点,即附加的上下文数据应该从串行器发出。这似乎是最简单的方式,因为序列化程序将返回一个本地的Python数据类型,所有的渲染器都将知道如何呈现。



它的外观如何: / p>

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)
#在此处访问self.context以添加contex tual 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):
#在这种情况下,我们无法真正调用super,因为我们需要修改内部工作位
renderer_context = renderer_context或{}
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')

如果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, render_context)
如果response.exception:
data ['status_code'] = response.status_code
data.update(render_context)
返回数据

为了在上下文中添加数据,ViewSets提供了一个 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'
返回上下文

{'foo':'bar '} 现在可以在您的模板中使用。


The ViewSets do everything that I want, but I am finding that if I want to pass extra context to a template (with TemplateHTMLRenderer) then I will have to get at the functions that give responses.. (like list(), create(), etc)

The only way I can see to get into these is to completely redefine them in my ViewSet, but it seems that there should be an easy way to add a bit of context to the Template without having to redefine a whole set of methods...

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

Right now my code is looking like this but I will be wanting to add different context to the responses and I am trying to avoid redefining an entire method for such a small change. like this...

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

解决方案

Although I disagree with 'pleasedontbelong' in principle, I agree with him on the fact that the extra contextual data ought to be emitted from the serializer. That seems to be the cleanest way since the serializer would be returning a native python data type which all renderers would know how to render.

Heres how it would look like:

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

Serializer:

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

Now, foo should be available inside your template.

Another way to achieve this, in case you don't wish to mess with your serializers, would be to create a custom 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

To add data into the context, ViewSets provide a get_renderer_context method.

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'} should now be available in your template.

这篇关于Django REST Framework如何将上下文添加到ViewSet中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆