DRF: Content Negotiation#
DefaultContentNegotiation#
content_negotiation_classをカスタマイズするには、以下のようにします。
1
2
3
4
5
6
| from rest_framework.negotiation import DefaultContentNegotiation
class MyContentNegotiation(DefaultContentNegotiation):
def select_renderer(self, request, renderers, format_suffix=None):
# ここに処理を書きます。
pass
|
上記の例では、DefaultContentNegotiationを継承しています。
select_renderer()メソッドには、レンダラーを選択するための処理を書きます。
このメソッドは、リクエストオブジェクト、レンダラーのリスト、およびフォーマットサフィックスを引数として受け取ります。
ソース: Bing との会話 2023/5/12
ViewSetでの設定#
ViewSetごとにcontent_negotiation_classを設定することができます。
以下のように、ViewSetクラスのcontent_negotiation_class属性にカスタムクラスを指定します。
1
2
3
4
5
6
| from rest_framework.viewsets import ModelViewSet
class MyViewSet(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MySerializer
content_negotiation_class = MyContentNegotiation
|
上記の例では、MyContentNegotiationというカスタムクラスを使用しています。このクラスは、前回の回答で紹介したものです。
バイナリファイルの処理#
バイナリレンダラ:
1
2
3
4
5
| from rest_framework_csv import renderers
class BinaryRenderer(renderers.BaseRenderer):
def render(self, data, media_type=None, renderer_context=None):
return data
|
ネゴシエータ:
1
2
3
4
5
6
7
8
9
10
11
12
13
| from rest_framework.negotiation import DefaultContentNegotiation
from mimetypes import guess_type
class AttachmentContentNegotiation(DefaultContentNegotiation):
def select_renderer(self, request, renderers, format_suffix=None):
try:
res = super().select_renderer(request, renderers, format_suffix=format_suffix)
return res
except Exception as e:
mt = format_suffix and guess_type(f"a.{format_suffix}")[0]
logger.info(f"{e}:BinaryRenderer for {format_suffix}")
return (base_renderers.BinaryRenderer(), mt)
|
1
2
3
4
5
6
7
8
9
| class AttachmentViewSet(viewsets.BaseModelViewSet):
permission_classes = [
permissions.AttachmentPermission,
]
filterset_class = filters.AttachmentFilter
serializer_class = serializers.AttachmentSerializer
queryset = models.Attachment.objects.order_by("id")
pagination_class = paginations.Pagination
content_negotiation_class = AttachmentContentNegotiation
|