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()),
posted @ 2020-07-13 20:41  群青-Xi  阅读(168)  评论(0编辑  收藏  举报