我想用Django的REST框架有一个API调用来保存和更新多个实例。 举例来说,假设我有一个“课堂”模式,可以有多个“老师”。 如果我想创建多个教师,后来更新所有教室的数字我会怎么做呢? 我一定要做出一个API调用每一个老师吗?
我知道,我们目前无法保存嵌套模型,但我想知道,如果我们能在平老师保存。 谢谢!
我想用Django的REST框架有一个API调用来保存和更新多个实例。 举例来说,假设我有一个“课堂”模式,可以有多个“老师”。 如果我想创建多个教师,后来更新所有教室的数字我会怎么做呢? 我一定要做出一个API调用每一个老师吗?
我知道,我们目前无法保存嵌套模型,但我想知道,如果我们能在平老师保存。 谢谢!
我知道这是问前一段时间,但现在我发现它同时试图弄清楚这一点我自己。
事实证明,如果你通过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
,所以在我的串行I类重写__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', )
发布的数据列表网址这一观点的格式如下:
[
{'loads':'foo','of':'bar','fields':'buzz'},
{'loads':'fizz','of':'bazz','fields':'errrrm'}
]
创建了两个资源,这些细节。 这很好。
我来到了类似的结论丹尼尔Albarral,但这里有一个更简洁的解决方案:
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)
这里是另一种解决方案,你不需要重写你的串行__init__
方法。 只需重写你的观点的(ModelViewSet) 'create'
的方法。 请注意, many=isinstance(request.data,list)
。 这里many=True
当您发送对象的数组来创建和False
当您发送只是一个。 通过这种方式,可以节省一个项目,一个列表!
from rest_framework import status, viewsets
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)
我不能完全弄清楚得到request.DATA从字典转换为数组 - 这是对我能力的汤姆Manterfield的解决方案正常工作的限制。 这里是我的解决方案:
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)
我认为最好的aprouch尊重框架propoused架构将是创建这样一个mixin:
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)
编辑:
正如罗杰·柯林斯认为她的反应是更聪明的覆盖比“创造”的get_serializer方法。
你可以简单地覆盖get_serializer
方法在APIView,并通过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)
该通用视图页面Django的REST框架的文档指出ListCreateAPIView普通视图“用于读写终端来代表模型实例的集合”。
这就是我将开始寻找(和我要去实际上,因为我们将在我们的项目需要此功能一声不好)。
还需要注意的是例子通用视图页面上碰巧使用ListCreateAPIView
。
我想出了简单的例子post
Serializers.py
from rest_framework import serializers
from movie.models import Movie
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = [
'popularity',
'director',
'genre',
'imdb_score',
'name',
]
Views.py
from rest_framework.response import Response
from rest_framework import generics
from .serializers import MovieSerializer
from movie.models import Movie
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
class MovieList(generics.ListCreateAPIView):
queryset = Movie.objects.all().order_by('-id')[:10]
serializer_class = MovieSerializer
permission_classes = (IsAuthenticated,)
def list(self, request):
queryset = self.get_queryset()
serializer = MovieSerializer(queryset, many=True)
return Response(serializer.data)
def post(self, request, format=None):
data = request.data
if isinstance(data, list): # <- is the main logic
serializer = self.get_serializer(data=request.data, many=True)
else:
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
这些线是多实例的实际逻辑 -
data = request.data
if isinstance(data, list): # <- is the main logic
serializer = self.get_serializer(data=request.data, many=True)
else:
serializer = self.get_serializer(data=request.data)
如果你正与许多=真糊涂,看到这
当我们发送的数据将是内部的list
有点像这样-
[
{
"popularity": 84.0,
"director": "Stanley Kubrick",
"genre": [
1,
6,
10
],
"imdb_score": 8.4,
"name": "2001 : A Space Odyssey"
},
{
"popularity": 84.0,
"director": "Stanley Kubrick",
"genre": [
1,
6,
10
],
"imdb_score": 8.4,
"name": "2001 : A Space Odyssey"
}
]
最直接的方法我遇到:
def post(self, request, *args, **kwargs):
serializer = ThatSerializer(data=request.data, many=isinstance(request.data, list))
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)