DRF10 large Interface

Custom Respoense

Although we already use, rest_framework the Response, but the code is still a little redundant, so they can rewrite their own (specific packaging requirements may be more practical to change)

Rewrite

from rest_framework.response import Response

class APIResponse(Response):
    # 格式化data
    def __init__(self, status=0, msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs):
        # data默认加上json的response基础有数据状态码和数据状态信息
        data = {  
            'status': status,
            'msg': msg
        }
        # 如果后台有数据,响应数据
        if results is not None:  
            data['results'] = results
        # 后台的一切自定义响应数据直接放到响应数据data中
        data.update(**kwargs)  
        super().__init__(data=data, status=http_status, headers=headers, exception=exception)

use

#查询正确,修改默认的状态码,和msg和http状态码
return APIResponse(status=1,msg="单查 error",http_status=400)

#查询错误,使用默认的msg和状态码
return APIResponse(results=user_data)

base table modles

modles a common field inside the table, the table can be extracted to the substrate

Note that the base table

Set up embedded abstract meta class to True, the default is False (creates this table is False)

is_delete field

I used to do tombstone, because the data is valuable

class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    create_time = models.DateTimeField(auto_now_add=True)
    class Meta:
        # 基表必须设置abstract,基表就是给普通Model类继承使用的,设置了abstract就不会完成数据库迁移完成建表
        abstract = True

Models to physical logical foreign key foreign key

Off characteristics associated

There is no association between the key sheet 1, but logically associated foreign key (it is to be noted that, because there is no physical constraints, so to secure data on the logical operation)
2, will not affect the efficiency of breaking the association database query, but will greatly improve the efficiency of database CRUD (because to do less step to determine whether there is a foreign key operating data)

db_constraint

Off the association, but also to cascade (default cascading deletes), so to set up their own, as follows

db_constraint=False

on_delete-- cascade delete

By default there are in django1.x in the 2.x must implement their own

on_delete=models.CASCADE

Note-many exceptions

1. actually-many foreign key relationship table, ORM default relationship table two foreign keys are concatenated

2.ManyToManyField field does not provide the settings on_delete, if you want to set the table to cascade, only manually define the relationship table

作者没了,详情也没:on_delete=models.CASCADE
出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING

#下面两个比较类似
部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL
部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT

related_name

Foreign key columns to forward the query field, related_name a reverse lookup field

obj = models.Author.objects.filter(pk=1).first()
print(obj.detail.mobile)
obj2 = models.AuthorDetail.objects.filter(pk=1).first()
print(obj2.author.name)

Case

# 多表:Book,Publish,Author,AuthorDetail
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    create_time = models.DateTimeField(auto_now_add=True)
    class Meta:
        abstract = True

class Book(BaseModel):
    name = models.CharField(max_length=16)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)

    authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)

    # 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
    @property
    def publish_name(self):
        return self.publish.name
        
    @property
    def author_list(self):
        temp_author_list = []
        for author in self.authors.all():
            temp_author_list.append({
                'name': author.name,
                'sex': author.get_sex_display(),
                'mobile': author.detail.mobile
            })
        return temp_author_list

class Publish(BaseModel):
    name = models.CharField(max_length=16)
    address = models.CharField(max_length=64)

class Author(BaseModel):
    name = models.CharField(max_length=16)
    sex = models.IntegerField(choices=[(0, '男'),(1, '女')], default=0)

class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11)

    author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)

DRF multi-table relations

One-to-many

Option One

In fact, like the use of the self-definition of the characteristics of the field, you can go to get the return value data alone, the last in the sequence data, but be aware that argument can not be returned in the form of the object, or can not support this target sequence in addition to other objects of

fields

 fields = ('name', 'price', 'publish_name', 'author_list')

models

    #self为book对象,直接用它进行多表查询,返回想要的数据
    
    @property
    def publish_name(self):
        return self.publish.name
    @property
    def author_list(self):
        temp_author_list = []
        for author in self.authors.all():
            temp_author_list.append({
                'name': author.name,
                'sex': author.get_sex_display(),
                'mobile': author.detail.mobile
            })
        return temp_author_list

Option II - Custom depth

Compared

Contrast the above objects can not pass, this method directly to the serializer used to use other data, can serialize the other recording data

But we can not deserialize, and will direct error

premise

If only the interface needs to check, it can also be used to customize the depth of the sub-sequences is accomplished

class PublishModelSerializer(serializers.ModelSerializer):
   子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False,不唯一many=True
    #只有带外键的记录能这样搞
    books = BookModelSerializer(many=True)
    class Meta:
        model = models.Publish
        fields = ('name', 'address', 'books')

Single investigation, the investigation group

    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            if not book_obj:
                return APIResponse(1, 'pk error', http_status=400)
            book_data = serializers.BookModelSerializer(book_obj).data
            return APIResponse(results=book_data)

        book_query = models.Book.objects.filter(is_delete=False).all()
        return APIResponse(0, 'ok', data=serializers.BookModelSerializer(book_query, many=True).data)

Single delete, delete group

    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        # 将单删群删逻辑整合,都设为列表形式统一
        if pk:
            pks = [pk]
        else:
            pks = request.data.get('pks')
        # 前台数据有误(主要是群删没有提供pks)
        if not pks:
            return APIResponse(1, 'delete error', http_status=400)
        # 只要有操作受影响行,就是删除成功,反之失败
        # 这里使用的是存orm的方法
        rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
        if rows:
            return APIResponse(0, 'delete ok')
        return APIResponse(1, 'delete failed')

Tenzin, population growth

To be noted that the sequence and deserialization setting field

principle

In fact, it calls the create method ListSerializer, and then create increased ModelSerializer cycle call, and finally returns the result ListSerializer cycle

note

But ListSerializer provides only create method does not provide the update method, change the method to achieve the group but also their own rewrite achieve (why not rewrite it? May be because the group needs to change too complicated)

    def post(self, request, *args, **kwargs):
        request_data = request.data
        #通过数据类型判断单增还是群增
        if isinstance(request_data, dict): 
            book_ser = serializers.BookModelSerializer(data=request_data)
            #手动处理错误
            if book_ser.is_valid():
                book_obj = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
            return APIResponse(1, msg=book_ser.errors)
            
        elif isinstance(request_data, list) and len(request_data) != 0 : 
            book_ser = serializers.BookModelSerializer(data=request_data, many=True)
            #自动处理错误
            book_ser.is_valid(raise_exception=True)
            book_obj_list = book_ser.save()
            return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
        else:
            return APIResponse(1, 'data error', http_status=400)

Single overall change, the overall change group

Since the default method calls ListSerializer create, but ListSerializer not rewrite, so we need to achieve their own

Rewrite

As long as the overriding implementation cycle call, ModelSerializer the update function on the line, and finally returns the results

class BookListSerializer(serializers.ListSerializer):

    #父级ListSerializer没有通过update方法的实现体,需要自己重写
    def update(self, instance, validated_data):
        
        #self.child能反向获取ModelSerializer函数
        return [
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]

Binding

Add a binding relationship with ListSerializer in ModelSerializer, note added to the meta inside

        # 关联ListSerializer完成群增群改
        list_serializer_class = BookListSerializer
   def put(self, request, *args, **kwargs):
        """
        单整体改:前台提交字典,接口 /books/(pk)/
        群整体改:前台提交列表套字典,接口 /books/,注每一个字典都可以通过pk
        """
        pk = kwargs.get('pk')
        request_data = request.data
        #单改
        if pk: 
            try:
                book_obj = models.Book.objects.get(pk=pk)
            except:
                return APIResponse(1, 'pk error')

            # 修改和新增,都需要通过数据,数据依旧给data,修改与新增不同点,instance要被赋值为被修改对象,这样两个值都有才会去调用update方法
            book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
        # 群改
        else:  
            #如果数据不是列表形式或为空数据不符合要求
            if not isinstance(request_data, list) or len(request_data) == 0:
                return APIResponse(1, 'data error', http_status=400)

            # 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作(危险操作)
            obj_list = []
            data_list = []
            for dic in request_data:
                #由于内部数据不一定是dict,所以修改操作要注意异常
                try:
                    #如果数据不是字典就会报错
                    pk = dic.pop('pk')
                    try:
                        #可能没有这个id的数据可以修改
                        obj = models.Book.objects.get(pk=pk, is_delete=False)
                        obj_list.append(obj)
                        data_list.append(dic)
                    except:
                        pass
                except:
                    return APIResponse(1, 'data error', http_status=400)

            book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True)
            #最后一次全部校验
            book_ser.is_valid(raise_exception=True)
            book_obj_list = book_ser.save()
            return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)

Single locally modified, all locally modified

Local and global difference is that the data do not provide all of the field

So long as the coupled partial = True deserializing method on the line

# 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)

Little knowledge

Above ListSerializer, ModelSerializer may bind to each other is so achievable

Wl mm below the existing content code have zx content

class wl():
    @classmethod
    def w(cls):
        print(cls.child)

class zx():
    class meta():
        @classmethod
        def m(cls):
            mm=wl
            mm.child=zx
            print(mm)
            return mm

zx.meta.m().w()


<class '__main__.wl'>
<class '__main__.zx'>

Guess you like

Origin www.cnblogs.com/zx125/p/11909401.html