DRF - 序列化器删除嵌套序列化器
DRF - serializer drops nested serializers
TL;DR: DRF 在验证最外层序列化程序时丢弃内部序列化对象。
我正在使用 django 2.0,django-rest-framework 3.7.7,python 3.
我想构建一个在数据库中执行搜索的 REST 端点,使用 POST 中收到的一些参数(我想避免 GET 调用,这可能会被缓存)。参数应该像 OR(这就是为什么我将所有字段设置为不需要的原因),并且我在提取查询集时使用 django Q queries 解决了这个问题。
我在 app/models.py
中有以下 django 模型:
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 -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
[]
即使刚刚创建了相应设置了 birth_place 的 Person 对象。
我放在视图 post 方法中的两个打印语句 return:
initial_data: {'birth_place': {'name': 'Berlin', 'country': 'Germany'}}
after is_valid: OrderedDict()
所以 DRF 似乎在验证时删除了嵌套关系。
我应该如何指定解析和验证嵌套关系?任何建议表示赞赏。
PS:我是否通过使用 POST 提出请求来强制执行错误的设计?我认为因为搜索不是幂等的,它可能包含一个人的敏感数据(名字、姓氏、出生日期等)。
我需要一个安全的操作(搜索不会更改数据)但不是幂等的(两次不同时间的搜索可能不同)。
最初我开始使用 generics.ListAPIView,但 list() 仅适用于 GET。如果有办法让它接受 POST 请求,它会非常有效。
如评论中@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
TL;DR: DRF 在验证最外层序列化程序时丢弃内部序列化对象。
我正在使用 django 2.0,django-rest-framework 3.7.7,python 3.
我想构建一个在数据库中执行搜索的 REST 端点,使用 POST 中收到的一些参数(我想避免 GET 调用,这可能会被缓存)。参数应该像 OR(这就是为什么我将所有字段设置为不需要的原因),并且我在提取查询集时使用 django Q queries 解决了这个问题。
我在 app/models.py
中有以下 django 模型:
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 -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
[]
即使刚刚创建了相应设置了 birth_place 的 Person 对象。 我放在视图 post 方法中的两个打印语句 return:
initial_data: {'birth_place': {'name': 'Berlin', 'country': 'Germany'}}
after is_valid: OrderedDict()
所以 DRF 似乎在验证时删除了嵌套关系。
我应该如何指定解析和验证嵌套关系?任何建议表示赞赏。
PS:我是否通过使用 POST 提出请求来强制执行错误的设计?我认为因为搜索不是幂等的,它可能包含一个人的敏感数据(名字、姓氏、出生日期等)。 我需要一个安全的操作(搜索不会更改数据)但不是幂等的(两次不同时间的搜索可能不同)。
最初我开始使用 generics.ListAPIView,但 list() 仅适用于 GET。如果有办法让它接受 POST 请求,它会非常有效。
如评论中@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