![](/img/trans.png)
[英]How to add namespace url to a django-rest-framework router 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
)。
步驟如下:
覆蓋get_renderer_context
上的get_renderer_context
方法(如已建議的那樣):
def get_renderer_context(self): context = super().get_renderer_context() context['foo'] = 'bar' return context
子類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.