Как создать несколько экземпляров модели с помощью Django Rest Framework?
Я хотел бы сохранить и обновить несколько экземпляров с помощью Django Rest Framework с помощью одного вызова API. Например, допустим, у меня есть модель "Класс", которая может иметь несколько "Учителей". Если бы я хотел создать несколько учителей и позже обновить все номера своих классов, как бы я это сделал? Должен ли я выполнять вызов API для каждого преподавателя?
Я знаю, что в настоящее время мы не можем сохранить вложенные модели, но я хотел бы знать, можем ли мы сохранить его на уровне учителя.
Спасибо!
Ответы
Ответ 1
Я знаю, что это было задано некоторое время назад, но я нашел его, пытаясь понять это сам.
Оказывается, если вы передаете many=True
при создании экземпляра класса serializer для модели, он может затем принять несколько объектов.
Это упоминается здесь в django rest framework docs
В моем случае мое мнение выглядело так:
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'}
]
Создал два ресурса с этими деталями. Что было приятно.
Ответ 2
Я пришел к аналогичному выводу, как Даниэль Альбаррал, но здесь более сжатое решение:
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)
Ответ 3
Я не мог понять, как получить запрос .DATA для преобразования из словаря в массив, что ограничивало мою способность к решению Tom 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)
Ответ 4
Я думаю, что лучше всего уважать пропущенную архитектуру фреймворка - создать такой микс:
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)
Затем вы можете переопределить CreateModelMixin ModelViewSet следующим образом:
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)
EDIT:
Как говорит Роджер Коллинз в ее ответ, более умный, чтобы перезаписать метод get_serializer, чем 'create'.
Ответ 5
Страница Общие виды в Документация Django REST Framework что ListCreateAPIView общий вид "используется для конечных точек чтения и записи для представления коллекции экземпляров модели".
Что бы я начал искать (и я собираюсь на самом деле, так как нам тоже понадобится эта функциональность в нашем проекте).
Обратите внимание также, что examples на странице Generic Views использует ListCreateAPIView
.
Ответ 6
Здесь другое решение, вам не нужно переопределять ваш метод сериализации __init__
. Просто переопределите метод просмотра (ModelViewSet) 'create'
. Обратите внимание на many=isinstance(request.data,list)
. Здесь 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)
Ответ 7
Вы можете просто перезаписать метод 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)