Day 23 Advanced usage of DRF serializer and related source code

Day 23 Advanced usage of DRF serializer and related source code

1. Modify and delete the interface

According to restful specifications- resource operation is determined by the request method

So at present we need different different routes and view class to achieve this function

1. Routing configuration

# urls.py

url(r'^book/$', views.Book.as_view()),  # get 所有的查询 以及增加
url(r'^book/(?P<id>\d+)$', views.BookInfo.as_view()),  # 单个的 删 改 查

2. CBV view preparation

# views.py

class BookInfo(APIView):
    # 查询单本书的操作,与查询多本相同 都是拿到对象后,经过序列器返回
    def get(self, request, id):
        one_book = models.Book.objects.filter(id=id).first()
        if one_book:
            ser = serializer.BookSerializer(instance=one_book)
            return Response(ser.data)
        else:
            raise ValidationError('找不到这本书哦!')
    
    # 在这里我们就可以不用通过序列器了,直接返回操作信息就好了
    def delete(self, request, id):
        one_book = models.Book.objects.filter(id=id)
        if one_book:
            one_book.delete()
            return Response('删除成功!')
        else:
            raise ValidationError('找不到这本书哦!')
    # 这里需要经过序列器 步骤相同
    def patch(self, request, id):
        result = {
    
    'code': 100, 'msg': '修改成功!'}
        one_book = models.Book.objects.filter(pk=id)
        print(request.data)
        # 在实例化 对象的时候 我们也要将修改的数据 data 传进去,partial是否为单个 可以不加
        ser = serializer.BookSerializer(data=request.data, instance=one_book, partial=True)
        if ser.is_valid():
            ser.save() # 这里我们需要注意的是 要调用save方法  我们要在序列器中重写啊update
            return Response(result)  # 不能返回 ser.data会报错
        else:
            result['code'] = 101
            result['data'] = '该书不存在!'
            return Response(result)

3. Sequencer

def update(self, instance, validated_data):  # 会自动补全后面的参数
    instance.update(**validated_data)  # 直接赋值就可以了 
    print(instance)
    return instance  # 将结果返回

Let's use postman to demonstrate

image-20201105153442931

(It should be the third record here. I got it wrong, but the result is the same!)

Two, the source of advanced serializer usage

routing

    url(r'^book/', views.Book.as_view()),

model

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)
    
    def author_func(self):
        return '这是' + self.author + '写的'

Serializer

class Book(serializers.Serializer):
    name = serializers.CharField(max_length=32)
    price = serializers.CharField()
    author = serializers.CharField(min_length=1)
    publish = serializers.CharField()
    # 执行表模型中的 author_func方法,并把 返回值赋予  book_info
    # 注意 字段名不能和 表模型方法 相同
    book_info = serializers.CharField(source='author_func')

View function

class Book(APIView):
    
    def get(self,request, *args, **kwargs):
        books = models.Book.objects.all()
        ser = serializer.Book(instance=books, many=True)
        return Response(ser.data)

test

image-20201105161756028

Three, model class serializer

The original Serilizer is not directly related to the table model. The model serializer ModelSerilizer has a corresponding relationship with the table model.

1. Rewrite the table structure

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.ManyToManyField(to='Author')
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    address = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=32)
    salary = models.IntegerField()
    phone = models.CharField(max_length=11)

2. Routing configuration

url(r'^bookmodel/', views.BookModel.as_view()),

3. View configuration

class BookModel(APIView):
    
    def get(self, request, *args, **kwargs):
        books = models.Book.objects.all()
        ser = serializer.BookModel(instance=books, many=True)
        return Response(ser.data)

4. Specify the fields

4.1 Use fields to clarify the fields, the __all__table name contains all the fields, you can also specify which fields are specific, such as

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = ['name', 'author', 'publish']

image-20201105170522921

4.2 Use exclude to clearly exclude which fields

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        exclude = ['author', 'publish']

image-20201105170834770

4.3 The default ModelSerializer uses the primary key as the associated field, but we can use depth to simply generate the nested representation. The depth should be an integer, indicating the number of levels of nesting. Such as:

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'  # 查询所有
        depth = 1

image-20201105171154039

4.4 Specify read-only fields

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'
        read_only_fields = ['name', 'author', 'publish']

image-20201105191515313

4.5 Write only fields

Fields that need to be passed in to deserialize

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'
        write_only_fields = ('name', 'author', 'publish')

image-20201105192115808

4.6 Add additional parameters

We can use the extra_kwargs parameter to add or modify the original option parameters for ModelSerializer

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = ['name', 'author', 'publish']
        depth = 1
        extra_kwargs = {
    
    'name': {
    
    'min_length': 2}}

image-20201105192955467

Fourth, the SerializerMethodField of advanced usage

Make good use of SerializerMethodField to optimize unnecessary queries

Option One

depth

Option II

In fact, in many cases we don’t need to query BookObject owned byAuthorObject, many times we just need one BookOwned AuthorThe total number of objects is fine, if necessary, check again AuthorThe list is detailed. At this point we can use the SerializerMethodField provided by Django REST framework to achieve this purpose

Reduce the use of depth

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'
    
    author = serializers.SerializerMethodField()
    # 名字不可以概念 实例化那个 就只能 get_字段名
    def get_author(self, obj):
        # name = obj.author.name  # 也可以单个返回
        dic = {
    
    'name':obj.author.name,'salary':obj.author.name}
        return dic

third solution

Use serialization class nesting

class Author(serializers.ModelSerializer):
    class Meta:
        # 关联
        model = models.Author
        # 选取需要显示的字段
        fields = ['name', 'salary']


class BookModel(serializers.ModelSerializer):
    # 要实例化哦
    # 也要和 book的字段对应
    author = Author()
   
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'

image-20201105195723570

Five, drf request and response

1. Request

	-data :前端以post请求提交的数据都在它中
    -FILES :前端提交的文件
    -query_params:就是原来的request.GET
    -重写了 __getattr__
    	-使用新的request.method其实取得就是原生request.method(通过反射实现)

2. Response

	-from rest_framework.response import Response
    -data:响应的字典
    -status:http响应的状态码
    	-drf提供给你了所有的状态码,以及它的意思
        from rest_framework.status import HTTP_201_CREATED
    -template_name:模板名字(一般不动),了解
    -headers:响应头,字典
    -content_type:响应的编码方式,了解

3. Encapsulate a response yourself and inherit the response of drf

According to the restful specification, it is necessary to return status code and error information, but different methods cause a lot of code redundancy, we can write a response ourselves, so that we can directly call.

    
 # 自己封装一个Response对象
      class CommonResponse:
        def __init__(self):
            self.code=100
            self.msg=''
        @property
        def get_dic(self):
            return self.__dict__

4. Through configuration, select the display form of the default template (browser mode, json mode)

Like django, drf has a default setting, which contains various display modes, we can change this configuration in django settings

# 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
	-配置文件方式(全局)
        -如果没有配置,默认有浏览器和json
            -drf有默认配置文件
            from rest_framework.settings import DEFAULTS
            REST_FRAMEWORK = {
    
    
            'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
                'rest_framework.renderers.JSONRenderer',  # json渲染器
                'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
            )
        	}
    -在视图类中配置(局部)
    	-粒度更小
        -class BookDetail(APIView):
    		renderer_classes=[JSONRenderer,]

Six, many=True source code analysis, local and global hook source code analysis

1 many=True
	-__init__----->一路找到了BaseSerializer---》__new__决定了生成的对象是谁
    
2 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data)
	-Serializer这个类的:self.run_validation
def run_validation(self, data=empty):
        value = self.to_internal_value(data)  # 局部字段自己的校验和局部钩子校验
        try:
            self.run_validators(value)
            value = self.validate(value)  # 全局钩子的校验
        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))
        return value

7. What is the idempotence of an interface and how to make it?

Interface idempotence, what is it, and how to make it

8. Interface

What is an interface?

The interface only defines some methods, but does not implement it. It is mostly used in program design. It is only designed to have what functions, but it does not realize any functions. These functions need to be inherited by another class (B) and then be inherited by class B To achieve one or all of the functions.

Personal understanding, when used for collaborative development, different people implement each method in the interface in different classes.

In python, interfaces are implemented by abstract classes and abstract methods. Interfaces cannot be instantiated, and can only be inherited by other classes to implement corresponding functions.

I personally feel that the interface is not that important in python, because if you want to inherit the interface, you need to implement each of the methods, otherwise it will report a compilation error. It is better to directly define a class, and the method implementations are all pass, let the child The class overrides these functions.

Of course, if there is a mandatory requirement, all implementation classes must be written in accordance with the definition in the interface, and then the interface must be used.

In fact, it is the behavior of unifying subclasses

Python has three ways to restrict subclasses

  • Throw exception limit
  • abc module restrictions
  • Artificial restriction (duck type)

Guess you like

Origin blog.csdn.net/A1L__/article/details/109519797