Django rest框架,在同一个ModelViewSet中使用不同的序列化器
我想提供两个不同的序列化器,但是能够从ModelViewSet
所有工具中受益:
- 在查看对象列表时,我希望每个对象都有一个redirect到其细节的url,并且使用目标模型的
_ _ unicode _ _
显示其他关系。 例:[ { "membri": [ "emilio", "michele", "luisa", "ivan", "saverio" ], "creatore": "emilio", "url": "http://127.0.0.1:8000/database/gruppi/2/", "nome": "universitari", "descrizione": "unitn!", "accesso": "CHI" } ]
- 查看对象的详细信息时,我想使用默认的
HyperlinkedModelSerializer
,例如:{ "url": "http://127.0.0.1:8000/database/gruppi/2/", "nome": "universitari", "descrizione": "unitn!", "creatore": "http://127.0.0.1:8000/database/utenti/3/", "accesso": "CHI", "membri": [ "http://127.0.0.1:8000/database/utenti/3/", "http://127.0.0.1:8000/database/utenti/4/", "http://127.0.0.1:8000/database/utenti/5/", "http://127.0.0.1:8000/database/utenti/6/", "http://127.0.0.1:8000/database/utenti/7/" ] }
我设法按照以下方式按照我的意愿完成所有这些工作:
serializers.py
# serializer to use when showing a list class ListaGruppi(serializers.HyperlinkedModelSerializer): membri = serializers.RelatedField(many = True) creatore = serializers.RelatedField(many = False) class Meta: model = models.Gruppi # serializer to use when showing the details class DettaglioGruppi(serializers.HyperlinkedModelSerializer): class Meta: model = models.Gruppi
views.py
class DualSerializerViewSet(viewsets.ModelViewSet): """ ViewSet providing different serializers for list and detail views. Use list_serializer and detail_serializer to provide them """ def list(self, *args, **kwargs): self.serializer_class = self.list_serializer return viewsets.ModelViewSet.list(self, *args, **kwargs) def retrieve(self, *args, **kwargs): self.serializer_class = self.detail_serializer return viewsets.ModelViewSet.retrieve(self, *args, **kwargs) class GruppiViewSet(DualSerializerViewSet): model = models.Gruppi list_serializer = serializers.ListaGruppi detail_serializer = serializers.DettaglioGruppi # etc.
基本上,我检测到用户正在请求列表视图或详细视图,并更改serializer_class
以适应我的需要。 虽然我对这段代码并不满意,但它看起来像一个肮脏的黑客,最重要的是, 如果两个用户在同一时间请求一个列表和一个细节呢?
有没有更好的方式来实现这个使用ModelViewSets
或我必须回退使用GenericAPIView
?
编辑:
以下是如何使用自定义基础ModelViewSet
执行此操作的方法:
class MultiSerializerViewSet(viewsets.ModelViewSet): serializers = { 'default': None, } def get_serializer_class(self): return self.serializers.get(self.action, self.serializers['default']) class GruppiViewSet(MultiSerializerViewSet): model = models.Gruppi serializers = { 'list': serializers.ListaGruppi, 'detail': serializers.DettaglioGruppi, # etc. }
覆盖你的get_serializer_class
方法。 这个方法在您的模型mixins中用来检索正确的Serializer类。
请注意,还有一个get_serializer
方法返回正确的序列化器的实例
class DualSerializerViewSet(viewsets.ModelViewSet): def get_serializer_class(self): if self.action == 'list': return serializers.ListaGruppi if self.action == 'retrieve': return serializers.DettaglioGruppi return serializers.Default # I dont' know what you want for create/destroy/update.
你可能会发现这个mixin很有用,它覆盖了get_serializer_class方法,并允许你声明一个将action和serializer类映射到常用行为的dict。
class MultiSerializerViewSetMixin(object): def get_serializer_class(self): """ Look for serializer class in self.serializer_action_classes, which should be a dict mapping action name (key) to serializer class (value), ie: class MyViewSet(MultiSerializerViewSetMixin, ViewSet): serializer_class = MyDefaultSerializer serializer_action_classes = { 'list': MyListSerializer, 'my_action': MyActionSerializer, } @action def my_action: ... If there's no entry for that action then just fallback to the regular get_serializer_class lookup: self.serializer_class, DefaultSerializer. Thanks gonz: http://stackoverflow.com/a/22922156/11440 """ try: return self.serializer_action_classes[self.action] except (KeyError, AttributeError): return super(MultiSerializerViewSetMixin, self).get_serializer_class()
基于@gonz和@ user2734679答案我创build了这个小型的python包 ,它提供了一个ModelViewset子类的function。 下面是它的工作原理。
from drf_custom_viewsets.viewsets.CustomSerializerViewSet from myapp.serializers import DefaltSerializer, CustomSerializer1, CustomSerializer2 class MyViewSet(CustomSerializerViewSet): serializer_class = DefaultSerializer custom_serializer_classes = { 'create': CustomSerializer1, 'update': CustomSerializer2, }