zoukankan      html  css  js  c++  java
  • 组件化10大接口

    组件化10大接口

    表设计

    基表

    Model类的内部配置Meta类要设置abstract=True,这样的Model类就是用来作为基表

    多表:Book,Publish,Author,AuthorDetail

    1. 基表必须设置abstract,基表就是给普通Model类继承使用的,
    2. 设置了abstract就不会完成数据库迁移完成建表
    3. abstract 目的就是只为了继承设置,并且告诉django,不要进行建立这个表格

    表断关联

    db_constraint=False

    1. 表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
    2. 断关联后不会影响数据库查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
    3. 断关联一定要通过逻辑保证表之间数据的安全
    4. 断关联 db_constraint=False,将表之间的关系断掉,可以在逻辑上依旧可以连表
    5. 级联关系
      • 作者没了,详情也没:on_delete=models.CASCADE,删除作者,详情也会一并删除,级联删除
      • 出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING,删除出版社,书的出版社不变,不删除级联
      • 部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL,删除个人的部门,设置外键字段为空
      • 部门没了,员工进入默认部门(默认值):default=0,on_delete=models.SET_DEFAULT。删除个人的部门,设置所有的外键字段为0
      • 对对表不能设计on_delete

    ORM外键设计

    1、一对多:外键放在多的一方
    2、多对多:外键放在常用的一方
    3、一对一:外键放在不常用的一方
    4、外键字段为正向查询字段,related_name是反向查询字段

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

    有作者可以没有详情,删除作者,详情一定会被级联删除

    外键字段为正向查询字段,related_name是反向查询字段

    related_name='books',反向查询可以直接点books,反向查询的字段
    db_constraint=False,去掉外键建立的关联
    on_delete=models.DO_NOTHING,不执行级联删除

    # ManyToManyField字段不提供设置on_delete,如果想设置关系表级联,只能手动定义关系表
        authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
    

    表设计

    from django.db import models
    from django.conf import settings
    # 一、基表
    # Model类的内部配置Meta类要设置abstract=True,这样的Model类就是用来作为基表
    
    # 多表: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,基表就是给普通Model类继承使用的,
            # 设置了abstract就不会完成数据库迁移完成建表
            # abstract 目的就是只为了继承设置,并且告诉django,不要进行建立这个表格
    
            abstract = True  # 抽象的表
    
    
    class Book(BaseModel):# 继承表
        name = models.CharField(max_length=16)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        # related_name='books',反向查询可以直接点books,反向查询的字段
        # db_constraint=False,去掉外键建立的关联
        # on_delete=models.DO_NOTHING,不执行级联删除
        publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
        # 重点:多对多外键实际在关系表中,ORM默认关系表中两个外键都是级联
        # db_constraint=False
        # ManyToManyField字段不提供设置on_delete,如果想设置关系表级联,只能手动定义关系表
        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)
        # 有作者可以没有详情,删除作者,详情一定会被级联删除
        # 外键字段为正向查询字段,related_name是反向查询字段
        author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)
    

    响应模块格式化response(二次封装)

    返回信息

    格式:

    {
    	'status':0,
    	'msg':"",
    	'results':'',
    	...
    }
    
    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基础有数据状态码和数据状态信息
                'status': status,
                'msg': msg
            }
            if results is not None:  # 后台有数据,响应数据
                data['results'] = results
            data.update(**kwargs)  # 后台的一切自定义响应数据直接放到响应数据data中
            super().__init__(data=data, status=http_status, headers=headers, exception=exception)
    
    

    自定义异常

    在使用drf的时候,验证与is_valid(raise_exception=True)冲突,因此使用

    from rest_framework.views import exception_handler as drf_exception_handler
    from rest_framework.response import Response
    def exception_handler(exc, context):
        # drf_exception_handler的执行结果就是异常信息的Response对象或None
        # 是Response对象可以直接返回
        # 是None可以从exc中拿到异常信息,从context拿到是谁出现的异常,自己格式化成Response对象返回
        # 重点:自定义异常模块目的是记录异常信息到日志文件 - 产品阶段
        response = drf_exception_handler(exc, context)
        if response is None:
            response = Response({'detail': '%s' % exc}, status=500, exception=True)
        # logging.error(response.data)
        return response
    

    全局配置

    配置settings.py

    REST_FRAMEWORK = {
        # 异常
        # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',#系统异常
        'EXCEPTION_HANDLER': 'api.utils.exception_handler',#重写异常
    
    }
    

    序列化

    # 了解
    fields = '__all__'#返回所有
    exclude = ('id', )#除了id 其他的返回
    
     depth = 1#连表深度查询返回
        
    
    #下面俩个不能一起使用
    fields = '__all__'#返回所有
    exclude = ('id', )#除了id 其他的返回
    
    from rest_framework import serializers
    from . import models
    class BookListSerializer(serializers.ListSerializer):
        # 1、create方法父级ListSerializer已经提供了
        # def create(self, validated_data):
        #     # 通过self.child来访问绑定的ModelSerializer
        #     print(self.child)
        #     raise Exception('我不提供')
    
        # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
        def update(self, instance, validated_data):
            # print(instance)
            # print(validated_data)
            return [
                self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
            ]
    
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        # 通过BookModelSerializer.Meta.list_serializer_class来访问绑定的ListSerializer
        class Meta:
            # 关联ListSerializer完成群增群改
            #################################################################
            list_serializer_class = BookListSerializer
    
            model = models.Book
            # fields = ('name', 'price', 'publish', 'authors')
            # fields = ('name', 'price', 'publish_name', 'author_list')
            # 了解
            # fields = '__all__'
            # exclude = ('id', )
            # depth = 1
            # 序列化与反序列化整合
            fields = ('name', 'price', 'publish_name',
                      'author_list', 'publish', 'authors')
            extra_kwargs = {
                'publish': {
                    'write_only': True
                },
                'authors': {
                    'write_only': True
                }
            }
    

    子序列化

    子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True

    只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)

    # 前提:如果只有查需求的接口,自定义深度还可以用子序列化方式完成
    class PublishModelSerializer(serializers.ModelSerializer):
        # 子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True
        # 注:只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)
        books = BookModelSerializer(many=True)
        class Meta:
            model = models.Publish
            fields = ('name', 'address', 'books')
    

    十大接口

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^books/$', views.BookAPIView.as_view()),
        url(r'^books/(?P<pk>d+)/$', views.BookAPIView.as_view()),
    ]
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from . import models, serializers
    from .response import APIResponse
    class BookAPIView(APIView):
    

    单查、群查

    # 单查、群查
        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)
    

    单删、群删

    # 单删、群删
        def delete(self, request, *args, **kwargs):
            """
            单删:前台数据为pk,接口为 /books/(pk)/
            群删:前台数据为pks,接口为 /books/
            """
            pk = kwargs.get('pk')
            # 将单删群删逻辑整合
            if pk:  # /books/(pk)/的接口就不考虑群删,就固定为单删
                pks = [pk]
            else:
                pks = request.data.get('pks')
            # 前台数据有误(主要是群删没有提供pks)
            if not pks:
                return APIResponse(1, 'delete error', http_status=400)
            # 只要有操作受影响行,就是删除成功,反之失败
            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')
    

    单增、群增

    # 单增、群增
        def post(self, request, *args, **kwargs):
            """
            单增:前台提交字典,接口 /books/
            群增:前台提交列表套字典,接口 /books/
            """
            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)
    

    单整体改、群整体改

    重写update(更新)方法

    父级ListSerializer没有通过update方法的实现体,需要自己重写

    class BookListSerializer(serializers.ListSerializer):
        # 1、create方法父级ListSerializer已经提供了
        # def create(self, validated_data):
        #     # 通过self.child来访问绑定的ModelSerializer
        #     print(self.child)
        #     raise Exception('我不提供')
    
        # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
        def update(self, instance, validated_data):
            # print(instance)
            # print(validated_data)
            return [
                self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
            ]
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        # 通过BookModelSerializer.Meta.list_serializer_class来访问绑定的ListSerializer
        class Meta:
            # 关联ListSerializer完成群增群改
            list_serializer_class = BookListSerializer
    
    

    单整体改、群整体改

    instance=obj

    # 修改和新增,都需要通过数据,数据依旧给data,修改与新增不同点,instance要被赋值为被修改对象
    book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
    
    
    
    # 单整体改、群整体改
        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要被赋值为被修改对象
                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)
    
                # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
                # 要考虑pk对应的对象是否被删,以及pk没有对应的对象
                # 假设pk3被删,pk100没有 => [obj1] + [{...}]
    
                # 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作
                obj_list = []
                data_list = []
                for dic in request_data:
                    # request_data可能是list,单内部不一定是dict
                    try:
                        pk = dic.pop('pk')
                        try:
                            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)
    
    

    单局部改、群局部改

    partial=True

    # 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
    book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)
    
    
     # 单局部改、群局部改
        def patch(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')
                # 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
                book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)
                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)
    
                # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
                # 要考虑pk对应的对象是否被删,以及pk没有对应的对象
                # 假设pk3被删,pk100没有 => [obj1] + [{...}]
    
                # 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作
                obj_list = []
                data_list = []
                for dic in request_data:
                    # request_data可能是list,单内部不一定是dict
                    try:
                        pk = dic.pop('pk')
                        try:
                            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, partial=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)
    
    

    升级版

    单改

    # 单改
        def _single_update(self, pk, data):
            try:
                instance = models.Worker.objects.get(pk=pk, is_delete=False)
                ser = serializers.WorkerModelSerializer(instance=instance, data=data, partial=True)
                ser.is_valid(raise_exception=True)
                obj = ser.save()
                return APIResponse(data=serializers.WorkerModelSerializer(obj).data)
            except:
                return APIResponse(1, 'pk error', http_status=400)
    
    

    群改

     # 群改
        def _many_updata(self, data):
            instance_list = []
            data_list = []
            for dic in data:
                try:
                    # 不是字典,数据错误
                    pk = dic.pop('pk')
                    if len(dic) == 0: raise Exception('随便')
                    try:
                        # pk没有,对应的obj没有,对应的obj已删除,该数据丢弃
                        obj = models.Worker.objects.get(pk=pk, is_delete=False)
                        instance_list.append(obj)
                        data_list.append(dic)
                    except:
                        pass
                except:
                    return APIResponse(1, 'data error', http_status=400)
    
            ser = serializers.WorkerModelSerializer(instance=instance_list, data=data_list, partial=True, many=True)
            ser.is_valid(raise_exception=True)
            obj_list = ser.save()
            return APIResponse(data=serializers.WorkerModelSerializer(obj_list, many=True).data)
    
    
    
        def patch(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            request_data = request.data
            if pk and isinstance(request_data, dict) and len(request_data) != 0:
                return self._single_update(pk, request_data)
            elif not pk and isinstance(request_data, list) and len(request_data) != 0:
                return self._many_updata(request_data)
            else:
                return APIResponse(1, 'data error', http_status=400)
    
    
  • 相关阅读:
    English 2
    速算24点
    心理学1
    从微服务到函数式编程
    034 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 01 流程控制概述
    033 01 Android 零基础入门 01 Java基础语法 03 Java运算符 13 运算符和表达式知识点总结
    032 01 Android 零基础入门 01 Java基础语法 03 Java运算符 12 运算符和if-else条件语句的综合案例——闰年问题
    031 01 Android 零基础入门 01 Java基础语法 03 Java运算符 11 运算符的优先级
    030 01 Android 零基础入门 01 Java基础语法 03 Java运算符 10 条件运算符
    029 01 Android 零基础入门 01 Java基础语法 03 Java运算符 09 逻辑“非”运算符
  • 原文地址:https://www.cnblogs.com/SkyOceanchen/p/11908991.html
Copyright © 2011-2022 走看看