我正在尝试让我的端点在被要求返回一个uri-list
时返回一个json字符串作为默认值。我在单元测试中对此进行了测试,如下所示:
[...]
headers = {'Accept': 'text/uri-list'}
response = self.client.get('/api/v1/licenses/', headers=headers)
[...]
我这样写了URIListRenderer
:
from rest_framework import renderers
class URIListRenderer(renderers.BaseRenderer):
media_type = 'text/uri-list'
def render(self, data, media_type='None', renderer_context=None):
return "\n".join(data).encode()
接下来,我尝试在我的视图中使用我的渲染器渲染响应:
class RestLicenses(APIView):
"""
List all licenses, or create a new license
"""
permission_classes = (IsAuthenticated,)
parser_classes = (MultiPartParser,)
renderer_classes = (JSONRenderer, URIListRenderer,)
def get(self, request, format=None,):
models = LicenseModel.objects.all()
if len(models) == 0 :
return Response('[]',status=204)
if request.META.get('headers') is not None :
if request.META.get('headers').get('Accept') == 'text/uri-list' :
result = [];
for m in models :
result.append(reverse('downloadLicense', args=[m.pk], request=request))
return Response(result, status=200)
serializer = LicenseJSONSerializer(request, models, many=True)
serializer.is_valid()
return HttpResponse(JSONRenderer().render(serializer.data), content_type='application/json', status=200)
但是,除了列表中的第一个渲染器外,似乎很难选择其他任何渲染器。如何使其选择我的URIListRenderer
而不是json呢?
答案 0 :(得分:2)
您的单元测试未正确设置标题。如here所述,在使用Django测试客户端时,您应该使用CGI样式标头:
response = self.client.get('/api/v1/licenses/', HTTP_ACCEPT='text/uri-list')
内容协商使用真实的HTTP Accept标头。在您的代码中,您检查是否设置了“标头”,但这不是真正的HTTP Accept标头。应该是:
if request.META.get('HTTP_ACCEPT') == "text/uri-list":
...
答案 1 :(得分:1)
这是方法finalize_response
中的代码块:
if isinstance(response, Response):
if not getattr(request, 'accepted_renderer', None):
neg = self.perform_content_negotiation(request, force=True)
request.accepted_renderer, request.accepted_media_type = neg
response.accepted_renderer = request.accepted_renderer
response.accepted_media_type = request.accepted_media_type
response.renderer_context = self.get_renderer_context()
如您所见,在执行内容协商之前,它会检查视图是否已经设置了所需的渲染器,如果不是,则尝试自行进行协商。 因此,您可以在get方法中执行此操作:
if request.META.get('headers') is not None :
if request.META.get('headers').get('Accept') == 'text/uri-list' :
request.accepted_renderer = URIListRenderer
result = [];
for m in models :
result.append(reverse('downloadLicense', args=[m.pk], request=request))
return Response(result, status=200)
您可能应该做的另一件事是将自定义渲染器类放在renderer_classes列表中JSONRenderer
之前。这样,它将在内容协商期间先检查特殊情况,然后再检查一般情况。怀疑请求格式也与JSOnRender匹配,并且使自定义渲染器不正确。希望这会有所帮助