Django Rest Framework:如果嵌套序列化程序

时间:2015-07-23 08:54:30

标签: django django-rest-framework

我正在使用Django ver 1.7和Django Rest Framework ver 3.1.3。

我有两个相互关联的模型如下:

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包含指向User(Django的auth_user模型)的OneToOne字段,Admin有一个指向Person的OneToOne字段。但是,我想为最终用户提供一个屏幕,一次性更新所有这些细节(类似于在一个模板中组合多个ModelForms)。

我已经创建了与每个​​模型相对应的显式序列化器,它们具有如下嵌套关系。

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

每个序列化程序都定义了一个显式的create()和update()方法,为简洁起见,我省略了这些方法。我可以看到这些没有被调用,因此在验证过程中可能会遇到错误。

当我执行GET操作时,Person或Admin api端点正确返回所有嵌套对象。

当我在Person上执行PUT或POST操作时,它接受可选字段中的空白输入。但是,如果在Admin对象上执行PUT或POST操作时,我将相同的字段保留为空白,则会按如下方式标记错误。

我的PUT请求是:

{
    "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_scan,document_number和home_phone保留为空白,但它们是可选字段,AdminSerializer应接受此字段。

已输入与用户相关的字段但我仍然收到错误“此字段是必需的”,就好像它们丢失一样。

我在这里缺少什么?如果我使用ModelSerializers,我将面临同样的问题。

1 个答案:

答案 0 :(得分:0)

Looking your code why don't you use modelserializers instead of serializer. In serializer level you can change the fields according to the requirements. You can change the required field to non-required fields in serializer and it won't be problem on model level.

serializers.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)

If you want to change the user field to non-required in PersonSerializer change the code as follows.

user = UserSerializer(required=False)