Django implements interface automation platform (thirteen) interface module Interfaces serializer and view [continuously updated]

related articles:

Django implements interface automation platform (12) custom function module DebugTalks serializer and view [continuously updated]_Do test meow sauce blog-CSDN blog

This chapter is a breakdown of the project. When viewing the content of this chapter, it should be viewed in conjunction with the overall project code:

Python django vue httprunner implements interface automation platform (final version)

1. Interfaces background and related interfaces

request method URI corresponding action Realize function
GET /Interfaces/ .list() Query the interface list
POST /Interfaces/ .create() Create a piece of data
GET /Interfaces/{id}/ .retrieve() Retrieve detailed data of an Interface
PUT /Interfaces/{id}/ update() Update all fields in a piece of data
PATCH /Interfaces/{id}/ .partial_update() Update some fields in a piece of data
DELETE /Interfaces/{id}/ .destroy() delete a piece of data
GET /Interfaces/{id}/configs/ Query the configuration information of an interface
POST /Interfaces/{id}/run/ Run all cases under a certain interface
GET /Interfaces/{id}/testcases/ Query the case list under Interface

Under a project, there will be multiple interfaces.

An interface has multiple cases.

1.1  Query Interface list

GET /Interfaces/ .list() Query the interface list

 Interface list, the interfaces of all projects are in this list.

1.2 Create interface  Interface

POST /Interfaces/ .create() Create a piece of data

1.3 Edit and update interface  Interface

PUT /Interfaces/{id}/ update() Update all fields in a piece of data

 

 

Second, the model class model

models.py

from django.db import models

from utils.base_models import BaseModel


class Interfaces(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('接口名称', max_length=200, unique=True, help_text='接口名称')
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                related_name='interfaces', help_text='所属项目')
    tester = models.CharField('测试人员', max_length=50, help_text='测试人员')
    desc = models.CharField('简要描述', max_length=200, null=True, blank=True, help_text='简要描述')

    class Meta:
        db_table = 'tb_interfaces'
        verbose_name = '接口信息'
        verbose_name_plural = verbose_name
        ordering = ('id',)

    def __str__(self):
        return self.name

This code is a Django model class called Interfaces that represents interface information.

This model class inherits from BaseModel and defines the following fields:

  • id: Auto-incremented primary key generated automatically.
  • name: Interface name, which is a character field with a maximum length of 200 characters and must be unique.
  • project: Foreign key field, associated to another model class named Projects, using cascade delete.
  • tester: tester, which is a character field with a maximum length of 50.
  • desc: Brief description, it is an optional character field, the maximum length is 200, and it is allowed to be empty.

In the Meta inner class of the model class, some metadata is defined:

  • db_table: Specifies the name of the database table as 'tb_interfaces'.
  • verbose_name: The readable name of the model class is 'interface information', which is used to display on the management interface.
  • verbose_name_plural: The plural readable name of the model class is the same as verbose_name.
  • ordering: Define the default sorting method as ascending order by id.

Finally, the model class defines a __str__() method that returns the name of the interface (name field value) as a string representation of the instance, which is convenient for debugging and viewing objects.

This model class represents an interface information, including fields such as the name of the interface, the project it belongs to, the tester, and a brief description.

3. Serializer


from rest_framework import serializers

from .models import Interfaces
from projects.models import Projects



class InterfaceModelSerilizer(serializers.ModelSerializer):
    project = serializers.StringRelatedField(label='所属项目名称', help_text='所属项目名称')
    project_id = serializers.PrimaryKeyRelatedField(label='所属项目id', help_text='所属项目id',
                                                    queryset=Projects.objects.all())

    class Meta:
        model = Interfaces
        exclude = ('update_datetime',)
        extra_kwargs = {
            "create_datetime": {
                "read_only": True,
                "format": "%Y年%m月%d日 %H:%M:%S"
            }
        }

    def to_internal_value(self, data):
        result = super().to_internal_value(data)
        result['project'] = result.pop('project_id')
        return result

 

This is a Django REST Framework serializer called InterfaceModelSerializer that is used to serialize and deserialize interface information.

The serializer inherits from ModelSerializer and defines the following fields and metadata:

  • project: through serializers.StringRelatedField, the associated project object is serialized into a string representation, and the label is "name of the project to which it belongs".
  • project_id: Serialize the associated project object to its primary key ID through serializers.PrimaryKeyRelatedField, the label is "the project id", and the query set is Projects.objects.all().

In the model class, there is no project_id field, only project field. The value obtained for the project field is not passed in by the user, but is queried based on the table information. So we need to manually add the corresponding value of the project field in the serializer.

In the Meta inner class, the following properties are defined:

  • model: Specifies that the model corresponding to the serializer is Interfaces.
  • exclude: Exclude fields that do not need to be serialized and deserialized, here the update_datetime field is excluded.
  • extra_kwargs: used to define additional field parameters, here set the create_datetime field to read-only, and specify the date and time format as "%YYear%mMonth%dDay%H:%M:%S".

In addition, the serializer also rewrites the to_internal_value() method, obtains the deserialized data by calling the method of the parent class, and assigns the value of the project_id field to the project field to match the name in the model class.

The serializer implements serialization and deserialization interface information, and provides some additional field parameters, data conversion and other functions.

Here's why the to_internal_value() method should be rewritten:

​​​​​​​result['project'] = result.pop('project_id')

Because in the model class, there is no project_id field, only the project field.

class Interfaces(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('接口名称', max_length=200, unique=True, help_text='接口名称')
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                related_name='interfaces', help_text='所属项目')
    tester = models.CharField('测试人员', max_length=50, help_text='测试人员')
    desc = models.CharField('简要描述', max_length=200, null=True, blank=True, help_text='简要描述')

The project_id field comes from

3.1 Extension: Rewrite to_internal_value() method

 3.1.1. ModelSerializer class introduction:

Five, DRF model serializer ModelSerializer

3.1.2 to_internal_value() original method

Inheritance relationship:

 

Override the to_internal_value() method, to_internal_value() is inherited from the Serializer class.

source code:

    def to_internal_value(self, data):
        """
        Dict of native values <- Dict of primitive datatypes.
        """
        if not isinstance(data, Mapping):
            message = self.error_messages['invalid'].format(
                datatype=type(data).__name__
            )
            raise ValidationError({
                api_settings.NON_FIELD_ERRORS_KEY: [message]
            }, code='invalid')

        ret = OrderedDict()
        errors = OrderedDict()
        fields = self._writable_fields

        for field in fields:
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            primitive_value = field.get_value(data)
            try:
                validated_value = field.run_validation(primitive_value)
                if validate_method is not None:
                    validated_value = validate_method(validated_value)
            except ValidationError as exc:
                errors[field.field_name] = exc.detail
            except DjangoValidationError as exc:
                errors[field.field_name] = get_error_detail(exc)
            except SkipField:
                pass
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret

The to_internal_value method is used to convert the incoming raw data data into an internal value, that is, to map the external data data to the attributes of the model.

The incoming raw data data:

  • The incoming raw data can be a dictionary type (Mapping), which is a data structure composed of key-value pairs. In this code, determine whether the incoming requirements are met by judging whether the data type is Mapping. If it is not a dictionary type, a validation error will be thrown. The data of the dictionary type can be in the form of {'key': 'value'}, where the key and value can be any legal Python data type.

1. In this method, first determine whether the incoming data is a dictionary type (Mapping). If it is not a dictionary type, a validation error is thrown and an error message is returned. Then, create an ordered dictionary ret for storing converted internal values, and an ordered dictionary errors for storing error messages during validation.

2. Next, get a list of writable fields (_writable_fields) and iterate through each of them. For each field, first try to get the field validation method (validate_method), and then get the value of the original data through the field's get_value(data) method.

3. Next, perform validation and conversion operations on the original value, use the run_validation method of the field to perform validation, and convert the original value to a validated value. If the field defines a validation method (validate_method), this method is called for further processing of the validated value.

During validation, a ValidationError or DjangoValidationError exception may be thrown, indicating that validation failed. At this time, the error information is saved in the errors dictionary, the field name is used as the key, and the error details are used as the value.

If a SkipField exception occurs during the verification process, it means skip the verification operation of this field and directly enter the next field.

Finally, if the errors dictionary contains error information, a ValidationError exception is thrown, which contains validation error information for all fields. If there are no errors, the converted internal value ret is returned.

To sum up, the to_internal_value method is the core method in Django REST Framework for converting external incoming data into internal values. It maps external data to model attributes through validation and conversion operations, and handles errors that may occur during validation.

The return value of the to_internal_value() method:

        """
        Dict of native values <- Dict of primitive datatypes.
        """

"Dict of primitive datatypes" refers to a dictionary whose values ​​are data of primitive datatypes. Common primitive data types include integers (int), floating-point numbers (float), strings (string), Boolean values ​​(boolean), and so on.

"Dict of native values" means a dictionary whose values ​​are values ​​of the native data type. In Python, these native data types are consistent with built-in data types, such as int, float, str, bool, etc.

Therefore, "Dict of native values ​​<- Dict of primitive datatypes" means converting the values ​​of primitive datatypes in a dictionary to the values ​​of corresponding native datatypes. This conversion process can be done through Python's built-in functions, such as using methods such as int(), float(), str(), bool(), etc. to convert the value to the corresponding native data type. The end result will be a dictionary with the same keys but values ​​of the native data type.

The return value of the to_internal_value method is usually a dictionary type (Mapping ), representing the converted internal value. In the code, the result variable is a dictionary that stores the processed data.

3.1.3 Rewrite to_internal_value() method

    def to_internal_value(self, data):
        result = super().to_internal_value(data)
        result['project'] = result.pop('project_id')
        return result

In this code, the to_internal_value method first calls the to_internal_value method of the parent class and passes in the parameter data. This method is inherited from the parent class, and the default implementation will convert the incoming data into an internal value.

Then, the line of code result['project'] = result.pop('project_id') takes the value whose key is 'project_id' from the dictionary and adds it to the result dictionary with 'project' as the key. At the same time, result.pop('project_id') will delete the key-value pair whose key is 'project_id' in the original dictionary.

Finally, return the processed result dictionary.

The function of this code is to extract the 'project_id' key-value pair from the incoming data, rename it to 'project', and then return the processed dictionary. In this way, the field renaming operation on the data can be realized.

4. View

class InterfaceViewSet(RunMixin, viewsets.ModelViewSet):
    queryset = Interfaces.objects.all()
    serializer_class = serializers.InterfaceModelSerilizer
    permission_classes = [permissions.IsAuthenticated]

 

Guess you like

Origin blog.csdn.net/qq_39208536/article/details/131764604
Recommended