【问题标题】:DRF - serializer drops nested serializersDRF - 序列化器删除嵌套序列化器
【发布时间】:2018-02-15 17:42:17
【问题描述】:

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 方法中的两个打印语句返回:

initial_data:   {'birth_place': {'name': 'Berlin', 'country': 'Germany'}}
after is_valid: OrderedDict()

所以看起来 DRF 在验证时丢弃了嵌套关系。

我应该如何指定解析和验证嵌套关系?任何建议表示赞赏。

PS:我是否通过使用 POST 发出请求来强制错误设计?我认为由于搜索不是幂等的,它可能包含一个人的敏感数据(姓名、姓氏、出生日期等)。 我需要一个安全的操作(搜索不会更改数据)但不是幂等的(两个不同时间的搜索可能不同)。

最初我开始使用 generics.ListAPIView,但 list() 仅适用于 GET。如果有办法让它接受 POST 请求,它会像一个魅力一样工作。

【问题讨论】:

  • 暂时没有什么可以玩的...但是删除read_only=True会影响它吗?
  • 看来你成功了 :)
  • 你得到了一点@JonClements。辛苦了一天,我还没有完全掌握 DRF :) 如果你把它写成答案,我可以接受它

标签: django python-3.x django-rest-framework django-2.0


【解决方案1】:

正如 cmets 中提到的@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

【讨论】:

    猜你喜欢
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 2020-05-04
    相关资源
    最近更新 更多