gpt4 book ai didi

python - Django REST Framework POST 嵌套对象

转载 作者:IT老高 更新时间:2023-10-28 20:44:05 30 4
gpt4 key购买 nike

我现在在使用 Django Rest Framework 时遇到了一个小问题。我正在尝试发布一个包含嵌套对象的对象。

这是我的 serializers.py :

class ClassSerializer(serializers.ModelSerializer):
class Meta:
model = Class
fields = ('number', 'letter')


class SubjectSerializer(serializers.ModelSerializer):
class Meta:
model = Subject
fields = ('title',)


class ExamSerializer(serializers.ModelSerializer):
subject = SubjectSerializer()
clazz = ClassSerializer()

class Meta:
model = Exam
fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')
depth = 1

def create(self, validated_data):
return Exam.objects.create(**validated_data)

def update(self, instance, validated_data):
instance.__dict__.update(**validated_data)
instance.save()

return instance

create()来自 views.py :
def create(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)

return Response(serializer.validated_data, status=status.HTTP_201_CREATED)

这是 postman 的回复:
Postman response

我在这里阅读了一些关于这个问题的帖子,但我仍然坚持下去。我尝试通过多种方式修复它,但它仍然返回 "This field is required." .

最佳答案

您正在处理的问题nested serialization .请在继续之前阅读链接的文档。

您的问题涉及 DRF 中的一个复杂问题领域,因此需要进行一些解释和讨论以了解序列化程序和 View 集的工作原理。

我来讨论代表你的问题SubjectClass通过对不同的 HTTP 方法使用不同的数据表示,通过相同的端点传输数据,因为当人们希望以嵌套格式表示他们的数据时,这通常是问题;他们希望为他们的用户界面提供足够的信息以供干净使用,例如通过下拉选择器。

默认情况下,Django 和 Django REST Framework (DRF) 通过它们的主键引用相关对象(您的 SubjectClass)。默认情况下,这些是使用 Django 自动递增的整数键。如果您想通过其他方式引用它们,则必须为此编写覆盖。有几种不同的选择。

  • 第一个选项是 特化您的创建和更新逻辑:通过一些其他属性引用您的类并自己手动编写查找以进行创建,或将您引用的键设置为 primary key 你的类(class)。您可以将类的名称、UUID 或任何其他属性设置为主数据库键,只要它是唯一的, single field (我提到这一点的原因是因为您目前正在查看您的 Class 模型,该模型由复合搜索(数字、字母)组成)。您可以覆盖 create 中的相关对象查找。例如, View 方法(用于 POST),但是您必须在 update 中处理类似的查找。查看方法也是如此(对于 PUT 和 PATCH)。
  • 其次,在我看来,最好的选择是 专门化您的对象表示:通常通过主键引用您的类并创建一个用于读取对象的序列化程序和一个用于创建和更新它的序列化程序。这可以通过序列化器类继承和覆盖您的表示轻松实现。在 POST、PUT、PATCH 等请求中使用主键来更新类引用和外键。


  • 选项 1:在创建和更新中使用任意属性查找类和主题:

    将嵌套类序列化程序设置为只读:
    class ExamSerializer(serializers.ModelSerializer):
    subject = SubjectSerializer(read_only=True)
    clazz = ClassSerializer(read_only=True)

    覆盖 View 的 create 以在自由格式属性上查找相关类。另外,请查看 how DRF implements this with mixins .您还必须覆盖您的 update正确处理这些的方法,并考虑到 PATCH (部分更新)除了 PUT 的支持(更新)如果你走这条路:
    def create(self, request):
    # Look up objects by arbitrary attributes.
    # You can check here if your students are participating
    # the classes and have taken the subjects they sign up for.
    subject = get_object_or_404(Subject, title=request.data.get('subject'))
    clazz = get_object_or_404(
    Class,
    number=request.data.get('clazz_number')
    letter=request.data.get('clazz_letter')
    )

    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save(clazz=clazz, subject=subject)
    headers = self.get_success_headers(serializer.data)

    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    选项 2:将序列化程序专门用于读写和使用主键;这是惯用的方法:

    首先定义一个您希望用于正常操作(POST、PUT、PATCH)的默认 ModelSerializer:
    class ExamSerializer(serializers.ModelSerializer)
    class Meta:
    model = Exam
    fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')

    然后使用您想要提供给它们以读取数据 (GET) 的表示类型覆盖必要的字段:
    class ExamReadSerializer(ExamSerializer):
    subject = SubjectSerializer(read_only=True)
    clazz = ClassSerializer(read_only=True)

    然后 specify the serializer you wish to use for different operations 为您的 View 集。这里我们返回嵌套的 Subject 和 Class 数据用于读取操作,但只使用它们的主键进行更新操作(简单得多):
    class ExamViewSet(viewsets.ModelViewSet):
    queryset = Exam.objects.all()

    def get_serializer_class(self):
    # Define your HTTP method-to-serializer mapping freely.
    # This also works with CoreAPI and Swagger documentation,
    # which produces clean and readable API documentation,
    # so I have chosen to believe this is the way the
    # Django REST Framework author intended things to work:
    if self.request.method in ['GET']:
    # Since the ReadSerializer does nested lookups
    # in multiple tables, only use it when necessary
    return ExamReadSerializer
    return ExamSerializer

    如您所见,选项 2 似乎不那么复杂且容易出错,仅包含 3 行基于 DRF(get_serializer_class 实现)的手写代码。只需让框架的逻辑为您计算出对象的表示、创建和更新。

    我见过许多其他方法,但到目前为止,这些方法为我生成了最少的代码来维护并以干净的方式利用 DRF 的设计。

    关于python - Django REST Framework POST 嵌套对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41312558/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com