wen*_*isa 20 python django rest json django-rest-framework
我现在正面临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
Run Code Online (Sandbox Code Playgroud)
而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)
Run Code Online (Sandbox Code Playgroud)
我在这里看过一些关于这个问题的帖子,但我仍然坚持下去.我试图用几种方法修复它,但它仍在返回"This field is required.".
Ale*_*kli 44
您正在处理嵌套序列化的问题.请在继续之前阅读链接的文档.
您的问题涉及DRF中复杂的问题区域,因此需要一些解释和讨论来理解序列化程序和视图集的工作原理.
我将通过对不同的HTTP方法使用不同的数据表示来讨论通过相同端点表示您的数据Subject和Class数据的问题,因为当人们希望以嵌套格式表示他们的数据时,这通常是个问题.他们希望为用户界面提供足够的信息以便清洁使用,例如通过下拉选择器.
默认情况下,Django和Django REST Framework(DRF )通过主键引用相关对象(您的Subject和Class).默认情况下,这些是使用Django自动递增整数键.如果你想通过其他方式引用它们,你必须为此编写覆盖.有几种不同的选择.
Class模型由复合(数字,字母)搜索词组成的复合搜索.例如,您可以在create视图方法(对于POST)中覆盖相关的对象查找,但是您也必须在update视图方法中处理类似的查找(对于PUT和PATCH).选项1:在创建和更新中使用任意属性查看类和主题:
将嵌套类序列化程序设置为只读:
class ExamSerializer(serializers.ModelSerializer):
subject = SubjectSerializer(read_only=True)
clazz = ClassSerializer(read_only=True)
Run Code Online (Sandbox Code Playgroud)
覆盖视图的创建以在自由格式属性上查找相关的类.另外,请查看DRF如何使用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)
Run Code Online (Sandbox Code Playgroud)
选项2:专门用于读取和写入序列化程序并使用主键; 这是惯用的方法:
首先定义一个默认的ModelSerializer,用于正常操作(POST,PUT,PATCH):
class ExamSerializer(serializers.ModelSerializer)
class Meta:
model = Exam
fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')
Run Code Online (Sandbox Code Playgroud)
然后使用要为其提供的表示形式覆盖必要的字段以读取数据(GET):
class ExamReadSerializer(ExamSerializer):
subject = SubjectSerializer(read_only=True)
clazz = ClassSerializer(read_only=True)
Run Code Online (Sandbox Code Playgroud)
然后指定要用于ViewSet的不同操作的序列化程序.这里我们返回嵌套的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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,选项2似乎相当简单且容易出错,在DRF(get_serializer_class实现)之上只包含3行手写代码.让框架的逻辑为您找出对象的表示和创建以及更新.
我已经看到了许多其他方法,但到目前为止,这些方法已经为我提供了最少的代码,并以干净的方式利用DRF的设计.
val*_*ame 13
不做任何额外类的更简单的方法是对自己进行序列化:
class ExamSerializer(serializers.ModelSerializer):
class Meta:
model = Exam
fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')
def to_representation(self, instance):
data = super().to_representation(instance)
data['subject'] = SubjectSerializer(
Subject.objects.get(pk=data['subject'])).data
data['clazz'] = ClassSerializer(
Class.objects.get(pk=data['clazz'])).data
return data
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16630 次 |
| 最近记录: |