• Book系列的群CURD操作


    Book系列群操作

    表设计与关联models.py

    from django.db import models
    
    # 一、基表
    # Model类的内部配置Meta类要设置abstract=True,这样的Model类就是用来作为基表
    # 基表不会在数据库内创建出来
    # 二、表断关联
    # 1、表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
    # 2、断关联后不会影响数据库查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
    # 3、断关联一定要通过逻辑保证表之间数据的安全,不要出现脏数据,代码控制
    # 4、断关联
    # 5、级联关系
    #       作者没了,详情也没:on_delete=models.CASCADE
    #       出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING
    #       部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL
    #       部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT
    # 三、ORM外键设计
    # 1、一对多:外键放在多的一方
    # 2、多对多:外键放在常用的一方
    # 3、一对一:外键放在不常用的一方
    # 4、外键字段为正向查询字段,related_name是反向查询字段
    
    # 一张表有且只有一个自增字段,有且只有一个主键
    class BaseModel(models.Model):
        is_delete = models.BooleanField(default=False)
        # auto_now_add=True 只要记录创建,不需要手动插入时间,自动把当前时间插入
        create_time = models.DateTimeField(auto_new_add=True)
        # auto_now=True,只要更新,就会把当前时间插入
        last_update_time = models.DateTimeField(auto_new=True)
        # import datetime
        # create_time=models.DateTimeField(default=datetime.datetime.now)
        class Meta:
            # 单个字段,有索引,有唯一
            # 多个字段,有联合索引,联合唯一
            abstract=True # 抽象表
    
    class Book(BaseModel):
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        #to_field 默认不写,关联到Publish主键
        #db_constraint=False  逻辑上的关联,实质上没有外键练习,增删不会受外键影响,但是orm查询不影响
        # 出版社被删,图书不受影响
        publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False)
        # 多对多关系不能设置on_delete,如果想设置关系表级联,只能手动定义关系表(纯手动或半自动)
        # 什么时候用自动,什么时候用手动?第三张表只有关联字段,用自动    第三张表有扩展字段,需要手动写
        authors = models.ManyToManyField(to='Author', db_constraint=False)
        
        @property # 将方法包成数据属性,不参与反序列化操作
        def publish_name(self):
            # 返回出版社名字
            return self.publish.name
        
        @property
        def author_list(self):
            # 使用列表生成式生成一个个的作者名字,返回列表
            return [instance.name for instance in self.authors.all()]
        
    class Author(BaseModel):
        name = models.CharField(max_length=32)
        gender = models.IntegerField(choices=((1, '男'), (2, '女')), default=1)
        # 作者被删,详情一定被删
        detail = models.OneToOneField(to='Detail', on_delete=models.CASCADE, db_constraint=False)
        
    class Detail(BaseModel):
        phton = models.CharField(max_length=11)
        
    class Publish(BaseModel):
        name = models.CharField(max_length=32)
        address = models.CharField(max_length=32)
    

    序列化器编写

    # ser.py
    from rest_framework import serializers
    from api import models
    # 通过查看源码可知,群增时父类ListSerializer已经帮我写了create方法,但是群改的update方法需要我们自己重写
    # 我们也可以在继承父类ListSerializer的BookListSerializer中重写create方法实现群增,但是没必要
    class BookListSerializer(serializers.ListSerializer):
        def update(self, instance, validated_data):
            # self.child就是BookModelSerializer
            return [self.child.update(instance[i], item) for i, item in enumerate(validated_data)]
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            # 通过list_serializer_class关联BookListSerializer,从而访问绑定的ListSerializer,实现群增群改
            list_serializer_class = BookListSerializer
            model = models.Book
            # 插拔式属性,进行序列化操作,数据属性(publish_name,author_list)不参与反序列化操作
            fields = ('pk', 'name', 'price', 'author_list', 'publish_name', 'publish', 'authors')
            extra_kwargs = {
                'publish': {'write_only': True},# 提交数据时填写,不会展示给用户看
                'publish_name': {'read_only': True}, # 只展示,不会提交
                'authors': {'write_only': True},
                'author_list': {'read_only': True}
            }
    

    使用GenericAPIView实现5个接口

    # views.py
    from rest_framework.generics import GenericAPIView
    from rest_framework import status
    from api import models
    from api import ser
    from utils.response import APIResponse # 封装的response对象
    
    class BooksGenericAPIView(GenericAPIView):
        queryset = models.Book.objects.all().filter(is_delete=False) # 筛选出所有没被删除的数据
        serializer_class = ser.BookModelSerializer # 写入好的序列化器
    
        # 单查、群查
        def get(self, request, *args, **kwargs):
            if kwargs:# 通过kwargs是否有值来判断是查询单个数据还是查询所有数据
                instance = self.get_object()
                serializer = self.get_serializer(instance=instance)
            else:
                book_list = self.get_queryset()
                serializer = self.get_serializer(instance=book_list, many=True)
            return APIResponse(message='查询成功', result=serializer.data) # 返回自定义格式的json数据
    
        # 单增、群增
        def post(self, request, *args, **kwargs):
            if isinstance(request.data, list): # 规定群增,前端传过来的必须是个列表
                # save()调用继承的父类LiseSerializer中的create方法
                serializer = self.get_serializer(data=request.data, many=True) 
            else:
                # save()调用BookModelSerializer的create方法
                serializer = self.get_serializer(data=request.data)
            # 使用全局异常处理进行异常捕获,以json格式返回异常
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return APIResponse(message='创建成功', result=serializer.data, status=status.HTTP_201_CREATED)
    
        # 单改、群改
        def put(self, request, *args, **kwargs):
            if kwargs:
                instance = self.get_object()
                # save()调用BookModelSerializer的update方法
                serializer = self.get_serializer(instance=instance, data=request.data)
                # 局部修改
                # 局部修改就是在整体修改基础上设置partial=True,或者将所有参与反序列化字段设置为required=False
                # serializer = self.get_serializer(instance=instance, data=request.data, partial=True)
            else:
                book_list = []# 用来存储书对象
                modify_list = []# 用来存储修改的数据
                for data in request.data:
                    pk = data.pop('pk')
                    book_list.append(models.Book.objects.get(pk=pk))# 将获取到的书对象追加到列表
                    modify_list.append(data)# 将需要修改的数据追加到列表
                # save()会调用我们自己重写的update方法(ListSerializer没有帮我们写群改的update)
                # BookModelSerializer通过list_serializer_class来关联BookListSerializer,从而访问绑定的ListSerializer从而实现群改,其中的self.child就是指BookModelSerializer
                serializer = self.get_serializer(instance=book_list, data=modify_list, many=True)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return APIResponse(message='修改成功', result=serializer.data)
    
        # 单删、群删
        def delete(self, request, *args, **kwargs):
            # 不管是单删还是群删都存入列表pks中,只需要通过__in来筛选即可
            pks = []
            if kwargs:
                pk = kwargs.get('pk')
                pks.append(pk)
            else:
                pks = request.data.get('pks')
            # 规定群删除传入格式{"pks":[]}
            res = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
            if not res:
                return APIResponse(code=101, message='要删除的数据不存在', status=status.HTTP_404_NOT_FOUND)
            return APIResponse(message='成功删除%s条数据' % res)
    

    路由设置

    # urls.py
    # 总路由:
        path('api/', include('api.urls'))
        
    # 子路由:
    	path('books/', views.BooksGenericAPIView.as_view()),
        re_path(r'books/(?P<pk>d+)', views.BooksGenericAPIView.as_view()),
    
  • 相关阅读:
    Nodejs 开发指南 Nodejs+Express+ejs 开发microblog开发心得
    转载 java学习注意点
    STM32f103的数电采集电路的ADC多通道采集程序
    时间复杂度与空间复杂度
    RS232串口通信详解
    实现扫码登录
    TCP/UDP区别与联系
    Tcp三次握手/四次挥手
    浅谈CSRF攻击方式
    图片淡入淡出
  • 原文地址:https://www.cnblogs.com/guanxiying/p/13295551.html
Copyright © 2020-2023  润新知