Mic*_*ays 5 python django django-rest-framework
在我的方法中,如果传入数据中未设置它,Serializer.validate我需要能够访问attrs['field']并回退,我想知道是否有一个通用的模式可以这样做。self.instance.field
以DRF 序列化器文档的对象级验证部分为例:
from rest_framework import serializers
class EventSerializer(serializers.Serializer):
description = serializers.CharField(max_length=100)
start = serializers.DateTimeField()
finish = serializers.DateTimeField()
def validate(self, attrs):
"""
Check that start is before finish.
"""
if attrs['start'] > attrs['finish']:
raise serializers.ValidationError("finish must occur after start")
return attrs
Run Code Online (Sandbox Code Playgroud)
(这使用正常的Serializer,但想象它是模型ModelSerializer的a Event。)
当创建或更新事件时,数据中包含start和属性,则此序列化程序将按预期工作。finish
但是,如果您提出如下请求:
client.patch(f"/events/{event.id}", {"start": "2021-01-01"})
Run Code Online (Sandbox Code Playgroud)
那么序列化器将会失败,因为尝试访问会attrs['finish']产生KeyError. 在这种情况下,我需要能够回退到self.instance.finish,因为start < finish验证仍然是必要的。
有解决这个问题的通用模式吗?
您可以通过在所有方法的开头添加一个代码片段来解决此问题validate:
def validate(self, attrs):
full_attrs = attrs
if self.instance is not None:
full_attrs = {
**self.to_internal_value(self.__class__(self.instance).data),
**full_attrs,
}
Run Code Online (Sandbox Code Playgroud)
然后使用full_attrs代替attrs. 这会将实例数据的序列化版本添加到attrs.
有更好的方法来实现这一点吗?
(这样做的一个“缺点”是,如果数据失去完整性,它可能会阻止其他有效的更新。因此,例如,如果开发人员直接更新数据库,从而晚于event.start,event.finishAPI 用户将无法再更新event.description因为此验证会失败。但我认为优点绝对大于缺点,至少对于我当前的用例而言。)
我将提出我对这个问题的看法,因为我在我的一个项目中遇到了这个问题。
我在模型层进行了验证检查,因为:
在模型层上验证它非常简单。您可以重写save模型类的方法或clean方法并在方法中运行该clean方法(或full_clean)save。更多详细信息请参见此处。
from django.db import models
from django.core.exceptions import ValidationError
class MyModel(models.Model):
start = ...
finish = ...
...
def clean(self):
if self.finish < self.start:
raise ValidationError("Finish must occur after start")
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
现在这是关于 django 的 ValidationError 的事情。DRF不知道如何处理。如果您将一些无效数据传递给序列化器,您将不会得到良好的 400 响应。要让 DRF 处理错误,您可以编写自己的自定义错误处理程序并将其设置EXCEPTION_HANDLER为settings.py.
# myapp/exceptions.py
from django.core.exceptions import ValidationError
from rest_framework.views import exception_handler
from rest_framework.response import Response
def django_error_handler(exc, context):
"""Handle django core's errors."""
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
if response is None and isinstance(exc, ValidationError):
return Response(status=400, data=exc.message_dict)
return response
Run Code Online (Sandbox Code Playgroud)
# settings.py
REST_FRAMEWORK = {
...,
'EXCEPTION_HANDLER': 'myapp.exceptions.django_error_handler'
}
Run Code Online (Sandbox Code Playgroud)
我注意到您正在为序列化器使用通用serializers.Serializer类。如果您已经有了一个Event模型,那么使用起来会更容易serializers.ModelSerializer,因为它抽象了很多对象创建/更新逻辑。另一个好处是,由于它将查看模型的字段定义,因此它会根据模型中指定字段的方式构建字段,因此您无需在序列化器中定义字段(例如,如果该字段有max_length,它将创建相应的具有最大长度的 DRF 字段)。
| 归档时间: |
|
| 查看次数: |
5573 次 |
| 最近记录: |