[Django Learning] (10) Model Serializer_Associated Field Serialization

This article is an in-depth explanation of model class serializers and how to serialize associated fields;

class ProjectModelSerializer(serializers.ModelSerializer):

    email = serializers.EmailField(write_only=True)

    interfaces = InterfaceModelSerializer(label='所属接口的信息', help_text='所属接口的信息',
                                          read_only=True, many=True)


    class Meta:
        model = ProjectsModel

        fields = ('name', 'leader', 'tester','programmer','publish_app','email','interfaces')
        extra_kwargs = {
            'id': {
                'read_only': True},
            'name': {'max_length': 10, 'min_length': 5,
                     'validators': [UniqueValidator(ProjectsModel.objects.all(), message="项目名称不可重复!"),
                                    is_contain_project_word]},
            'tester': {
                'max_length': 10, 'min_length': 5,
                'error_messages': {"min_length": "tester长度不能少于5位", "max_length": "tester长度不能大于10位",
                                   "required": "tester字段为必填项"}
            },
            'desc': {
                'allow_null': True, 'default': 'desc默认值'
            },
            'programmer':{'write_only': True},
            'publish_app':{'write_only': True}
        }

    def create(self, validated_data):
        validated_data.pop('email')
        return super().create(validated_data)

    def update(self, instance, validated_data):
        return super().update(instance, validated_data)

1. The use of model class serializers

 In the model serialization class above:

  • You can inherit the ModelSerializer class or a subclass of ModelSerializer to create a model serializer class;
    • The serializer field can be redefined in the model serializer class, and the priority is higher than the automatically generated field with the same name
    • If the newly defined field does not need to be stored, you need to delete the field when calling the create() method, such as the email field above

 Inner class class Meta:

  • model=specified model class
    • The model attribute must be specified in the Meta internal class, and the referenced model class;
    • Automatically generate serializer fields and related validation rules through the specified model class;
  • fields
    • You can use the fields attribute to specify which fields in the model class need to automatically generate serializer fields;
    • Specify some fields, for example fields = ('name', 'leader')
      • If there is no 'programmer', 'publish_app' in the fields, the front end can not pass these fields, even if the front end passes these two parameters, it will not be verified, and it will not be stored in the database in the end
      • There are 'programmer' and 'publish_app' in fields, 
        if the front end passes these two parameters
        • If the attribute is in read-only mode, it will not be validated, the return is empty, and the database is null
        • If the attribute is in write-only mode, it will be verified, and will be stored in the database at the end, and will not be returned to the front end
        • If the attribute is in read-write mode, it will be verified, and finally it will be stored in the database and returned to the front end
      • There are 'programmer' and 'publish_app' in the fields, if the front end does not pass these two parameters
        • If the property is in read-only mode, it will not be validated, and the return will be empty
        • If the attribute is in write-only mode, the verification fails, and these parameters need to be passed for error reporting
        • If the attribute is in read-write mode, the verification fails, and these parameters need to be passed for error reporting
    • Specify all fields, e.g. fields = '__all__'
    • Exclude certain fields, e.g. exclude=('name','leader')
  • extra_kwargs
    • Dictionary type; properties of model class fields can be set 
  •  Custom create method and update method
    • We can call the create method and update method of the parent class to replace the method we wrote

    def create(self, validated_data):
        validated_data.pop('email')
        return super().create(validated_data)

    def update(self, instance, validated_data):
        return super().update(instance, validated_data)

2. Serialization of associated fields

class InterfacesModel(BaseModel):

    id = models.IntegerField(primary_key=True, verbose_name="id主键", help_text="id主键")
    name = models.CharField(unique=True,max_length=200, verbose_name="接口名称", help_text="接口名称")
    tester = models.CharField(max_length=200, verbose_name="测试人员", help_text="测试人员")
    desc = models.CharField(max_length=200, verbose_name="简要描述", help_text="简要描述")

    # 数据表中,会创建名称为外键字段_id的字段名
    # project = models.ForeignKey("projects.ProjectsModel", on_delete=models.CASCADE)
    project = models.ForeignKey(ProjectsModel, on_delete=models.CASCADE,related_name="interfaces")

    # models.OneToOneField指定一对一的外键字段
    # models.ManyToManyField指定多对多的外键字段
    class Meta:
        db_table = "tb_interfaces"
        verbose_name = "接口表"

    def __str__(self):
        return self.name

1. Associate the slave table fields in the main table serializer class

 The main table serializer class does not add slave table fields by default. At this time, we need to manually define the slave table fields to be associated

  • One-to-many : If you define associated fields from the table in the parent table serializer class, and there are multiple data from the table, you must add many =True , and interfaces must be added to fields
  • Create the object of the serializer class of the slave table directly in the serialization object of the main table, and assign it to the field named "lowercase_set of the model class name of the slave table", and then set the "lowercase_set of the model class name of the slave table" "The character name is added to the fields attribute of the Meta subclass
    • If the main table associated field related_name is defined in the slave table
      • In the main table's serializer class, change the foreign key field name "from table model class name lowercase_set" to the value of the related_name attribute
        # interfaces = serializers.PrimaryKeyRelatedField(read_only=True, many=True)

    • If the master table associated field related_name is not defined in the slave table
      • Then the field name is: lowercase_set from the table model class name
        # interfaces_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
        

1. The output is the slave table id corresponding to the master table id associated with the slave table

        interfaces = serializers.PrimaryKeyRelatedField(read_only=True, many=True)

2. The output is the corresponding slave table name associated with the master table id

        interfaces=serializers.StringRelatedField(many=True)

 The __str__ method defined in the serializer class associated with the table will be called, and then output

3. The output is the slave table query set associated with the master table id and the slave table

        interfaces = InterfaceModelSerializer(label='information of the interface', help_text='information of the interface',read_only=True, many=True)

4. Customize the output association from a certain field attribute value of the table

interfaces=serializers.SlugRelatedField(slug_field='tester',read_only=True,many=True)

 

It is recommended to specify a unique key here , such as name or id, so as to distinguish which data in the parent table is associated

2. Associate the main table fields from the table serializer class

 Since the associated fields of the main table are defined in the model class from the table, the serializer class from the table defaults to create the associated fields of the main table

1. The output is the corresponding main table id associated with the main table id from the table

  • project=serializers.PrimaryKeyRelatedField(queryset=ProjectsModel.objects.all())
  • And the project should be added to the fields

 Create data from table

Query slave table data

 2. [StringRelatedField] outputs the name of the corresponding main table associated with the parent table id from the table

        project=serializers.StringRelatedField(many=True)

  The __str__ method defined in the serializer class associated with the main table will be called, and then output

 Remark:

StringRelatedField can only be used for serialized output;

3. [Main table serializer class] outputs the main table query set associated with the main table id from the table

        If the slave table---master table is a many-to- one relationship, there is no need to add the attribute many=True, otherwise an error will be reported

       project = ProjectModelSerializer(label='information of the project to which the interface belongs', help_text='information of the project to which the interface belongs',read_only=True)

4. [SlugRelatedField] Specify a field in the model class of the parent table (try to use a field with a unique constraint) for input or output

4.1 Only output this field

  • If you only need output, then add read_only=True
  • project = serializers.SlugRelatedField(slug_field='desc', read_only=True)

It is recommended to specify a unique key here , such as name or id, so as to distinguish which data in the parent table is associated 

 4.2 Both input and output

  • If deserializer input (validation) is required, queryset must be specified
  • project = serializers.SlugRelatedField(slug_field='desc', queryset=ProjectsModel.objects.all())

If it is not a unique field, an error may be reported:

projects.models.ProjectsModel.MultipleObjectsReturned: get() returned more than one ProjectsModel -- it returned 9!

[This error means that more than 1 model object was returned, but 9 were actually returned]

So we better set the unique key

Guess you like

Origin blog.csdn.net/weixin_43569834/article/details/131443463