DRF - сериализатор отбрасывает вложенные сериализаторы
TL; DR: DRF удаляет внутренний сериализованный объект при проверке самого внешнего сериализатора.
Я использую django 2.0, django-rest-framework 3.7.7, python 3.
Я хочу создать конечную точку REST, которая выполняет поиск в базе данных, используя некоторые параметры, полученные в POST (я хочу избежать вызовов GET, которые могут быть кэшированы). Параметры должны действовать как OR (именно поэтому я устанавливаю все поля как необязательные), и я решаю это с помощью запросов django Q при извлечении набора запросов.
У меня есть следующие модели Django в app/models.py
:
class Town(models.Model):
name = models.CharField(max_length=200)
province = models.CharField(max_length=2, blank=True, null=True)
zip = models.CharField(max_length=5)
country = models.CharField(max_length=100)
class Person(models.Model):
name = models.CharField(max_length=100)
birth_place = models.ForeignKey(Town, on_delete=models.SET_NULL,
null=True, blank=True,
related_name="birth_place_rev")
residence = models.ForeignKey(Town, on_delete=models.SET_NULL,
null=True, blank=True,
related_name="residence_rev")
И я написал следующие сериализаторы в app/serializers.py
:
class TownSerializer(serializers.ModelSerializer):
class Meta:
model = models.Town
fields = ("id", "name", "province", "zip", "country")
def __init__(self, *args, **kwargs):
super(TownSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class PersonSerializer(serializers.ModelSerializer):
birth_place = TownSerializer(read_only=True)
residence = TownSerializer(read_only=True)
class Meta:
model = models.Person
fields = ("id", "name", "birth_place", "residence")
def __init__(self, *args, **kwargs):
super(PersonSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
Затем я написал представление для предоставления интерфейса REST, в api/views.py
:
class PersonSearchList(views.APIView):
model_class = Person
serializer_class = PersonSerializer
permission_classes = (permissions.AllowAny,)
def post(self, request, format=None):
serializer = self.serializer_class(data=request.data)
print("initial_data", serializer.initial_data) ########
if serializer.is_valid():
self.data = serializer.validated_data
print(self.data) ########
queryset = self.get_queryset()
serialized_objects = self.serializer_class(queryset, many=True)
return Response(serialized_objects.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_queryset(self, *args, **kwargs):
orig_queryset = self.model_class.objects.all()
query_payload = self.data
# .. perform filtering using the query_payload data.
return queryset
И когда я пытаюсь выполнить запрос, например, curl:
$ curl -s -X POST -H "Content-Type: application/json" --data '{"birth_place": {"name": "Berlin", "country": "Germany"}}' http://127.0.0.1:8000/persons/ |python -m json.tool
[]
несмотря на то, что объект Person с установленным соответственно значением Birth_place был только что создан. Два оператора печати, которые я поместил в метод post представления, возвращают:
initial_data: {'birth_place': {'name': 'Berlin', 'country': 'Germany'}}
after is_valid: OrderedDict()
Так что похоже, что DRF отбрасывает вложенное отношение при проверке.
Как я должен указать, чтобы проанализировать и проверить также вложенные отношения? Любое предложение приветствуется.
PS: я заставляю неправильный дизайн, делая запрос с POST? Я подумал, что, поскольку поиск не идемпотентен, и он может содержать конфиденциальные данные (имя, фамилия, дата рождения и т. Д.) Человека. Мне нужно действие, которое является безопасным (поиск не изменяет данные), но не идемпотентно (поиск в два разных времени может быть разным).
Первоначально я начал использовать generics.ListAPIView, но list() работает только с GET. Если есть способ заставить его принимать запросы POST, он будет работать как шарм.
1 ответ
Как @Jon Clements♦
упоминается в комментариях, это решит вашу проблему
class PersonSerializer(serializers.ModelSerializer):
birth_place = TownSerializer()
residence = TownSerializer()
class Meta:
model = Person
fields = ("id", "name", "birth_place", "residence")
def __init__(self, *args, **kwargs):
super(PersonSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False