Django Rest框架:如果嵌套序列化程序中的可选字段为空,则PUT/POST失败
我使用的是Django 1.7版和Django Rest框架3.1.3版 我有两个相互关联的模型,如下所示:Django Rest框架:如果嵌套序列化程序中的可选字段为空,则PUT/POST失败,django,django-rest-framework,Django,Django Rest Framework,我使用的是Django 1.7版和Django Rest框架3.1.3版 我有两个相互关联的模型,如下所示: class Person(models.Model): name = models.CharField(max_length=200) GENDER_CHOICES = ( ('M', 'Male'), ('F', 'Female'), ('T', 'Transgender'), ) gender
class Person(models.Model):
name = models.CharField(max_length=200)
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
('T', 'Transgender'),
)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
address = models.CharField(max_length=1000)
work_phone = models.CharField(max_length=15, blank=True, null=True,
validators=[RegexValidator(regex='^[0-9]+$',
message='Phone number must contain only digits',
code='nomatch')])
home_phone = models.CharField(max_length=15, blank=True, null=True,
validators=[RegexValidator(regex='^[0-9]+$',
message='Phone number must contain only digits',
code='nomatch')])
mobile = models.CharField(max_length=15, blank=True, null=True,
validators=[RegexValidator(regex='^[0-9]+$',
message='Phone number must contain only digits',
code='nomatch')])
email = models.EmailField(blank=True)
date_of_birth = models.DateField()
user = OneToOneField(User, null=True, blank=True)
DOCUMENT_CHOICES = (
('DL', 'Driving License'),
('RC', 'Ration card'),
('PP', 'Passport'),
('NO', 'None'),
)
additional_document = models.CharField(max_length=2, choices=DOCUMENT_CHOICES)
document_number = models.CharField(max_length=10, blank=True, null=True)
document_scan = models.FileField(max_length=1000, blank=True, null=True)
photo = models.ImageField(blank=True,null=True)
class Admin(models.Model):
person = OneToOneField(Person)
# More fields will be added later
所以Person包含一个指向用户的OneToOne字段(Django的auth_用户模型),Admin包含一个指向Person的OneToOne字段。但是,我想为最终用户提供一个屏幕,一次更新所有这些细节(类似于在一个模板中组合多个模型)
我已经创建了与这些模型对应的显式序列化程序,它们具有如下嵌套关系
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(label='ID', read_only=True)
username = serializers.CharField(max_length=30)
password = serializers.CharField(max_length=128, style={'input_type': 'password'})
class PersonSerializer(serializers.Serializer):
id = serializers.IntegerField(label="ID", read_only=True)
user = UserSerializer()
name = serializers.CharField(max_length=200)
gender = serializers.ChoiceField(choices=['M', 'F', 'T'])
address = serializers.CharField(max_length=1000)
work_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
home_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
mobile = serializers.CharField(max_length=15, required=False, allow_null=True)
email = serializers.EmailField(required=False, allow_blank=True)
date_of_birth = serializers.DateField()
additional_document = serializers.ChoiceField(choices=['NO','DL', 'RC', 'PP'])
document_number = serializers.CharField(max_length=10, required=False, allow_null=True)
document_scan = serializers.FileField(max_length=1000, required=False, allow_null=True)
photo = serializers.ImageField(required=False, allow_null=True)
class AdminSerializer(serializers.Serializer):
id = serializers.IntegerField(label="ID", read_only=True)
person = PersonSerializer()
# More fields will be added later
user = UserSerializer(required=False)
每个序列化程序都定义了显式的create()和update()方法,为了简洁起见,我省略了这些方法。我可以看到这些没有被调用,因此在验证过程中可能会遇到错误
当我执行GET操作时,Person或AdminAPI端点将正确返回所有嵌套对象
当我对Person执行PUT或POST操作时,它接受可选字段中的空白输入。但是,如果在对管理对象执行PUT或POST操作时将相同的字段保留为空,则会按如下方式标记错误
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(label='ID', read_only=True)
username = serializers.CharField(max_length=30)
password = serializers.CharField(max_length=128, style={'input_type': 'password'})
class PersonSerializer(serializers.Serializer):
id = serializers.IntegerField(label="ID", read_only=True)
user = UserSerializer()
name = serializers.CharField(max_length=200)
gender = serializers.ChoiceField(choices=['M', 'F', 'T'])
address = serializers.CharField(max_length=1000)
work_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
home_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
mobile = serializers.CharField(max_length=15, required=False, allow_null=True)
email = serializers.EmailField(required=False, allow_blank=True)
date_of_birth = serializers.DateField()
additional_document = serializers.ChoiceField(choices=['NO','DL', 'RC', 'PP'])
document_number = serializers.CharField(max_length=10, required=False, allow_null=True)
document_scan = serializers.FileField(max_length=1000, required=False, allow_null=True)
photo = serializers.ImageField(required=False, allow_null=True)
class AdminSerializer(serializers.Serializer):
id = serializers.IntegerField(label="ID", read_only=True)
person = PersonSerializer()
# More fields will be added later
user = UserSerializer(required=False)
我的要求是:
{
"id": 1,
"person": {
"id": 1,
"user": {
"id": 2,
"username": "nina.sinha",
"password": "pbkdf2_sha256$12000$CjmifxpP1DDv$1622S7enIwnT+NcwhMKIEWrq8Uy7gQQJPQQueML21Sg="
},
"name": "Nina Sinha",
"gender": "F",
"address": "1234, 6th Cross, 7th Main Street",
"work_phone": "42011567",
"home_phone": "",
"mobile": "9854609658",
"email": "nina.sinha@yahoo.com",
"date_of_birth": "1985-04-03",
"additional_document": "NO",
"document_number": "",
"document_scan": null,
"photo": null
}
}
错误:
HTTP 400 Bad Request
Content-Type: application/json
Vary: Accept
Allow: GET, PUT, PATCH, HEAD, OPTIONS
{
"person": {
"document_scan": [
"The submitted data was not a file. Check the encoding type on the form."
],
"photo": [
"The submitted data was not a file. Check the encoding type on the form."
],
"document_number": [
"This field may not be blank."
],
"user": [
"This field is required."
],
"home_phone": [
"This field may not be blank."
]
}
}
字段document\u scan、document\u number和home\u phone保留为空,但它们是可选字段,AdminSerializer应该接受这一点
已经输入了与用户相关的字段,但我仍然收到错误“此字段是必需的”,好像它们丢失了一样
我错过了什么?如果我使用ModelSerializer,我会面临同样的问题。查看代码,为什么不使用ModelSerializer而不是serializer。在序列化程序级别,您可以根据需要更改字段。您可以将序列化程序中的必填字段更改为非必填字段,在模型级别上不会出现问题 序列化程序.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password')
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Person
fields = ('id', 'user', # specify other fields)
class AdminSerializer(serializers.ModelSerializer):
person = PersonSerializer()
class Meta:
model = Admin
fields = ('id', 'person', # specify other fields)
如果要在PersonSerializer中将用户字段更改为非必填字段,请按如下所示更改代码
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(label='ID', read_only=True)
username = serializers.CharField(max_length=30)
password = serializers.CharField(max_length=128, style={'input_type': 'password'})
class PersonSerializer(serializers.Serializer):
id = serializers.IntegerField(label="ID", read_only=True)
user = UserSerializer()
name = serializers.CharField(max_length=200)
gender = serializers.ChoiceField(choices=['M', 'F', 'T'])
address = serializers.CharField(max_length=1000)
work_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
home_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
mobile = serializers.CharField(max_length=15, required=False, allow_null=True)
email = serializers.EmailField(required=False, allow_blank=True)
date_of_birth = serializers.DateField()
additional_document = serializers.ChoiceField(choices=['NO','DL', 'RC', 'PP'])
document_number = serializers.CharField(max_length=10, required=False, allow_null=True)
document_scan = serializers.FileField(max_length=1000, required=False, allow_null=True)
photo = serializers.ImageField(required=False, allow_null=True)
class AdminSerializer(serializers.Serializer):
id = serializers.IntegerField(label="ID", read_only=True)
person = PersonSerializer()
# More fields will be added later
user = UserSerializer(required=False)
你能将你试图发送的post请求放入吗?内联编辑以添加put请求的内容。即使使用ModelSerializer,我也面临同样的问题。两级嵌套工作正常,但三级嵌套会抛出错误,抱怨字段丢失,即使我已经包含了字段,或者字段是可选的。我现在已经解决了这个问题,实现了AdminSerializer(包括PersonSerializer)的两级嵌套,并将用户作为Serializer.SlugRelatedField保留在PersonSerializer中。这似乎奏效了。