如何用Django Rest Framework创build多个模型实例?
我想通过一个API调用使用Django Rest Framework保存和更新多个实例。 例如,假设我有一个“教室”模式,可以有多个“教师”。 如果我想创build多个教师,然后更新他们所有的教室号码,我该怎么做? 我是否必须为每位老师进行API调用?
我目前知道我们不能保存嵌套的模型,但是我想知道我们是否可以将它保存在教师级别。 谢谢!
我知道这是前一阵子被问到的,但是我试图自己弄清楚这一点。
事实certificate,如果在实例化模型的序列化类时传递many=True
,则可以接受多个对象。
这在django rest框架文档中提到
对我而言,我的观点是这样的:
class ThingViewSet(viewsets.ModelViewSet): """This view provides list, detail, create, retrieve, update and destroy actions for Things.""" model = Thing serializer_class = ThingSerializer
我真的不想写一个样板的负载只是为了直接控制序列化器的实例化并传递many=True
,所以在我的序列化器类中,我重写了__init__
:
class ThingSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): many = kwargs.pop('many', True) super(ThingSerializer, self).__init__(many=many, *args, **kwargs) class Meta: model = Thing fields = ('loads', 'of', 'fields', )
以下列格式向此视图的列表url发布数据:
[ {'loads':'foo','of':'bar','fields':'buzz'}, {'loads':'fizz','of':'bazz','fields':'errrrm'} ]
用这些细节创build了两个资源。 这很好。
我得出了与Daniel Albarral类似的结论,但是这里有一个更简洁的解决scheme:
class CreateListModelMixin(object): def get_serializer(self, *args, **kwargs): """ if an array is passed, set serializer to many """ if isinstance(kwargs.get('data', {}), list): kwargs['many'] = True return super(CreateListModelMixin, self).get_serializer(*args, **kwargs)
我无法想象得到request.DATA从字典转换为数组 – 这是我对Tom Manterfield解决scheme工作能力的限制。 这是我的解决scheme:
class ThingSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): many = kwargs.pop('many', True) super(ThingSerializer, self).__init__(many=many, *args, **kwargs) class Meta: model = Thing fields = ('loads', 'of', 'fields', ) class ThingViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet ): queryset = myModels\ .Thing\ .objects\ .all() serializer_class = ThingSerializer def create(self, request, *args, **kwargs): self.user = request.user listOfThings = request.DATA['things'] serializer = self.get_serializer(data=listOfThings, files=request.FILES, many=True) if serializer.is_valid(): serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
然后我在客户端运行这个相当于:
var things = { "things":[ {'loads':'foo','of':'bar','fields':'buzz'}, {'loads':'fizz','of':'bazz','fields':'errrrm'}] } thingClientResource.post(things)
我认为尊重架构的最佳架构将是创build一个混合:
class CreateListModelMixin(object): def create(self, request, *args, **kwargs): """ Create a list of model instances if a list is provides or a single model instance otherwise. """ data = request.data if isinstance(data, list): serializer = self.get_serializer(data=request.data, many=True) else: serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
然后你可以像这样覆盖ModelViewSet的CreateModelMixin:
class <MyModel>ViewSet(CreateListModelMixin, viewsets.ModelViewSet): ... ...
现在在客户端你可以这样工作:
var things = [ {'loads':'foo','of':'bar','fields':'buzz'}, {'loads':'fizz','of':'bazz','fields':'errrrm'} ] thingClientResource.post(things)
要么
var thing = { 'loads':'foo','of':'bar','fields':'buzz' } thingClientResource.post(thing)
编辑:
正如罗杰·柯林斯(Roger Collins)在她的回应中所build议的,比“创build”更重要的是覆盖get_serializer方法。
Django REST Framework文档中的通用视图页面指出, ListCreateAPIView通用视图“用于读写端点来表示模型实例的集合”。
这就是我开始寻找的地方(而且我将会实际上,因为我们很快就会在我们的项目中需要这个function)。
另请注意,“通用视图”页面上的示例正好使用了ListCreateAPIView
。
您可以简单地覆盖get_serializer
中的get_serializer
方法,并将many=True
传递到基本视图的get_serializer
中,如下所示:
class SomeAPIView(CreateAPIView): queryset = SomeModel.objects.all() serializer_class = SomeSerializer def get_serializer(self, instance=None, data=None, many=False, partial=False): return super(SomeAPIView, self).get_serializer(instance=instance, data=data, many=True, partial=partial)
这是另一个解决scheme,你不需要覆盖你的序列化器__init__
方法。 只需重写您的视图(ModelViewSet)的'create'
方法。 注意many=isinstance(request.data,list)
。 在发送一个要创build的对象的数组的时候,这里有many=True
当你发送一个对象的时候,则是False
。 这样,你可以保存一个项目和一个列表!
from rest_framework import status from rest_framework.response import Response class ThingViewSet(viewsets.ModelViewSet): """This view snippet provides both list and item create functionality.""" #I took the liberty to change the model to queryset queryset = Thing.objects.all() serializer_class = ThingSerializer def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, many=isinstance(request.data,list)) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)