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, }