3. Serialization of DRF association table (query slave table data through master table)

Official documentation:

Serializers – Django REST framework Chinese site

Previous chapter:

2. Django REST Framework (DRF) serialization & amp; deserialization

1. Prerequisites

models.py

class MiaoClass(models.Model):
    id = models.AutoField(primary_key=True, verbose_name='id', help_text='id')
    classname = models.CharField(max_length=20, verbose_name='class name', help_text='class name')
    clasleader = models.CharField(max_length=10, verbose_name='name of class teacher', help_text='name of class teacher')
    classcode = models.IntegerField(unique=True, verbose_name='class code', help_text='class code')
    ifopens = models.BooleanField(default=True, verbose_name='whether school starts', help_text='whether school starts')
    classrate = models.IntegerField( verbose_name='class fee', help_text='class fee')

    classMeta:
        # i.db_table specifies the name of the created data table
        db_table = 'tb_class'
        # For the current data table, set the description of noon
        verbose_name = "class table"
        verbose_name_plural = "Class table"

2. When querying the master table data, display the primary key data (PrimaryKeyRelatedField) of the slave table

  1. The foreign key value of the associated table can be obtained by defining PrimaryKeyRelatedField
  2. If the data from the table is obtained through the parent table, by default you need to use the lowercase _set of the model class name from the table as the associated field name in the serializer
  3. If the realized_name parameter is specified when defining the foreign key field of the model class, then the realized_name parameter will be used as the associated field in the serializer class.

2.1 The serializer class of the main table

serializers.py

class ClassSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='class id', help_text='class id')
    classname = serializers.CharField(max_length=20, label='class name', help_text='class name')
    clasleader = serializers.CharField(max_length=10, label='name of class teacher', help_text='name of class teacher')
    classcode = serializers.IntegerField(label='class code', help_text='class code')
    ifopens = serializers.BooleanField(label='School starts', help_text='School starts')
    classrate = serializers.IntegerField(label='class fee', help_text='class fee')
    miaostudent_set = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id',read_only=True,many=True)

2.2 When querying the master table, display the primary key data (PrimaryKeyRelatedField) of the slave table

Implementation function:

When querying the master table, it is necessary to display the slave table data corresponding to the master table.

How to do it:

When defining the serializer class of the primary table, it is necessary to add a field related to the secondary table, named [slave table name model class name lowercase_set], and the value is the keyword serializers.PrimaryKeyRelatedField .

The final value is the primary key field of the secondary table.

 miaostudent_set = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id',read_only=True,many=True)

1. This field does not need to be entered during input. When serializing the output, this field needs to be displayed, so use

read_only=True,

2. One master table data may correspond to multiple slave table data, so you need to use many=True

2.2.1 Build Request

views.py

class ClassesView(View):

    # query all data
    def get(self, request):
        # get list data
        queryset = MiaoClass.objects.all()
        print(queryset)
        serializer = ClassSerializer(instance=queryset, many=True)
        return JsonResponse(serializer. data, safe=False)

class ClassesDetailView(View):
    def get(self, request, pk):
        # 1. It is necessary to verify whether pk exists in the database

        # 2. Read project data from the database
        try:
            class_obj = MiaoClass.objects.get(id=pk)
        except Exception as e:
            return JsonResponse({'msg': 'The parameter is wrong'}, status=400)
        serializer = ClassSerializer(instance=class_obj)

        return JsonResponse(serializer.data)

urls.py

 # Style: class view.as_view()
    path("classes/", views. ClassesView. as_view()),
    path('classes/<int:pk>/', views.ClassesDetailView.as_view()),

The value of miaostudent_set, which shows the primary key value of the slave table

2.3 Customize the attribute name of the slave table in the master table

In the above result, the displayed value is miaostudent_set (lowercase_set from table name model class name),

For the caller, who does not understand the meaning of this field, we want to customize the name of this field.

Such as defined as sid.

1. First modify the foreign key of the student table model class in models.py, and the associated name related_name=’sid’

class MiaoStudent(models.Model):
    sname = models.CharField(max_length=20, verbose_name='student name', help_text='student name')
    sgender = models.BooleanField(verbose_name='gender', help_text='gender')
    sage = models.IntegerField(verbose_name='age', help_text='age')
    sid = models.IntegerField(unique=True, verbose_name='student number', help_text='student number')
    sscore = models.IntegerField( verbose_name='score', help_text='score')
    classid = models.ForeignKey('miaoschool.MiaoClass',on_delete=models.CASCADE,verbose_name='class id',
                                help_text='class id',
                                related_name='sid')
classid = models.ForeignKey('miaoschool.MiaoClass',on_delete=models.CASCADE,verbose_name='class id',
                            help_text='class id',
                            related_name='sid')

2. In the serializer, use the sid field

sid = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id', read_only=True, many=True)
class ClassSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='class id', help_text='class id')
    classname = serializers.CharField(max_length=20, label='class name', help_text='class name')
    clasleader = serializers.CharField(max_length=10, label='name of class teacher', help_text='name of class teacher')
    classcode = serializers.IntegerField(label='class code', help_text='class code')
    ifopens = serializers.BooleanField(label='School starts', help_text='School starts')
    classrate = serializers.IntegerField(label='class fee', help_text='class fee')
    # miaostudent_set = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id',read_only=True,many=True)
    sid = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id', read_only=True, many=True)

Initiate the request again

The return value becomes cid

2.4 PrimaryKeyRelatedField

In PrimaryKeyRelatedField, you need to specify read_only=True, or queryset

Method 1: Specify read_only=True

Only serialized output, (when creating data, the user does not need to enter the field, when the user queries the data, the data of the field is displayed)

 sid = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id', read_only=True, many=True)

Method 2: Specify queryset=from the table model class.objects.all()

 sid = serializers.PrimaryKeyRelatedField(label='student id', help_text='student id',
                                             queryset = MiaoStudent. objects. all(),
                                             write_only=True,
                                             many=True)

Specify the queryset object of queryset=associated table, which is used to verify the parameters.

3. When querying the main table, display the __str__ of the model class of the slave table

Implemented features:

In the slave table model class, define the __str__ method. In the main table, when querying data, the __str__ data from the table will be output.

1. From the table model class, you need to define the __str__ method

 def __str__(self):
        return f"Name: {self.sname}, gender: {self.sgender}, age: {self.sage}, score: {self.sscore}"
class MiaoStudent(models.Model):
    sname = models.CharField(max_length=20, verbose_name='student name', help_text='student name')
    sgender = models.BooleanField(verbose_name='gender', help_text='gender')
    sage = models.IntegerField(verbose_name='age', help_text='age')
    sid = models.IntegerField(unique=True, verbose_name='student number', help_text='student number')
    sscore = models.IntegerField( verbose_name='score', help_text='score')
    classid = models.ForeignKey('miaoschool.MiaoClass',on_delete=models.CASCADE,verbose_name='class id',
                                help_text='class id',
                                related_name='sid')
    classMeta:
        # i.db_table specifies the name of the created data table
        db_table = 'tb_student'
        # For the current data table, set the description of noon
        verbose_name = "Student Information Form"
        verbose_name_plural = "Student Information Form"

    def __str__(self):
        return f"Name: {self.sname}, gender: {self.sgender}, age: {self.sage}, score: {self.sscore}"

2. In the serializer class of the parent table, you need to specify StringRelatedField(many=True)

sid = serializers. StringRelatedField(many=True)

Notice:

In StringRelatedField, read_only=True is added by default, and this field only serializes the output

3. Interface request, check the returned data

4. When querying the master table, display the specified field value of the slave table

1. Realize the function:

Query the data of the main table and display the specified fields from the table at the same time.

For example, I want to display the student name field sname from the table

2. SlugRelatedField(slug_field=”) specifies the slave table field and only serializes the output. (read only data)

sid = serializers.SlugRelatedField(slug_field='sname', many=True, read_only=True)

3. SlugRelatedField(slug_field=”) specifies the slave table field and deserializes the output. Verify when writing data

The queryset needs to be specified, and the associated field must have a unique constraint.

sid = serializers.SlugRelatedField(slug_field='sname',many=True,queryset=MiaoStudent.objects.all())

5. When querying the main table, display the specified multiple field values from the table

1. To show which fields of the slave table, we can define a serializer class separately.

For example, I want to display the sname and score fields from the table.

Define a serializer class that contains only these two fields.

class StudentINfoSerializer(serializers.Serializer):
    sname = serializers.CharField(label='student name', help_text='student name', max_length=10, min_length=1)
    sscore = serializers.IntegerField(label='student score', help_text='student score', max_value=100, min_value=0)

2. In the serializer of the main table, miaostudent_set = StudentSerializer()

miaostudent_set = StudentSerializer(read_only=True,many=True)

Notice:

  1. Custom serializers are subclasses of Field.
  2. In a custom serializer, when defining a field, the field must be a subclass of Field or Field, so in a custom serializer, when defining a field, the field can also be a serializer class.