drf--books系列表接口(单/多条--增删查改)

1.books系列表接口--teacher

# urls.py
from django.urls import path,re_path
from api import views
urlpatterns = [
    path('books/', views.BookAPIView.as_view()),
    re_path('books/(?P<pk>\d+)', views.BookAPIView.as_view()),
]
# views.py
from rest_framework.response import Response

from api import models
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from api.ser import BookModelSerializer

class BookAPIView(APIView):
    def get(self,request,*args,**kwargs):
        # 查询单个和查询所有,合到一起
        # 查所有
        book_list=models.Book.objects.all().filter(is_delete=False)
        book_list_ser=BookModelSerializer(book_list,many=True)
        return Response(data=book_list_ser.data)
        # 查一个

    def post(self,request,*args,**kwargs):
        # 具备增单条,和增多条的功能
        if isinstance(request.data,dict):
            book_ser=BookModelSerializer(data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        elif isinstance(request.data,list):
            # 现在book_ser是ListSerializer对象
            from rest_framework.serializers import ListSerializer
            # 根据many=True,调用的是ListSerializer类 的create方法
            book_ser = BookModelSerializer(data=request.data,many=True)  # 增多条
            print('--------',type(book_ser))
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            # 多条新增---》ListSerializer--》create方法
            # def create(self, validated_data):
            #   self.child是BookModelSerializer对象
            #   print(type(self.child))
            #     return [
            #         self.child.create(attrs) for attrs in validated_data
            #     ]
            return Response(data=book_ser.data)

    def put(self,request,*args,**kwargs):
        # 改一个和改多个
        # 改一个
        if kwargs.get('pk',None):
            book=models.Book.objects.filter(pk=kwargs.get('pk')).first()     
            # partial=True,判断是否是局部修改
            book_ser = BookModelSerializer(instance=book,data=request.data,partial=True)  # 改一个
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        else:
            # 改多个
            # 前端传递数据格式[{id:1,name:xx,price:xx},{id:1,name:xx,price:xx}]
            # 处理传入的数据  对象列表[book1,book2]  修改的数据列表[{name:xx,price:xx},{name:xx,price:xx}]
            book_list=[]
            modify_data=[]
            for item in request.data:
                # {id:1,name:xx,price:xx}
                pk=item.pop('id')
                book=models.Book.objects.get(pk=pk)
                book_list.append(book)
                modify_data.append(item)
            # 第一种方案,for循环一个一个修改
            # for i,si_data in enumerate(modify_data):
            #     book_ser = BookModelSerializer(instance=book_list[i], data=si_data)
            #     book_ser.is_valid(raise_exception=True)
            #     book_ser.save()
            # return Response(data='成功')
            # 第二种方案,重写ListSerializer的update方法
            book_ser = BookModelSerializer(instance=book_list,data=modify_data,many=True)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()  # ListSerializer的update方法,自己写的update方法
            return Response(book_ser.data)


    def delete(self,request,*args,**kwargs):
        #单个删除和批量删除
        pk=kwargs.get('pk')
        pks=[]
        if pk:
            # 单条删除
            pks.append(pk)
        # 不管单条删除还是多条删除,都用多条删除
        # 多条删除
        # {'pks':[1,2,3]}
        else:
            pks=request.data.get('pks')
        # 把is_delete设置成true
        # ret返回受影响的行数
        ret=models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True)
        if ret:
            return Response(data={'msg':'删除成功'})
        else:
            return Response(data={'msg': '没有要删除的数据'})
ser.py

# 如果序列化的是数据库的表,尽量用ModelSerializer

from rest_framework import serializers
from api import models

# 写一个类,继承ListSerializer,重写父类的update()
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    #     print(validated_data)
    #     return super().create(validated_data)
    
    def update(self, instance, validated_data):
        print(instance)
        print(validated_data)
        # 保存数据
        # self.child就是序列化类BookModelSerializer对象
        return [
            # self.child.update(对象,字典) for attrs in validated_data
            self.child.update(instance[i],attrs) for i,attrs in enumerate(validated_data)
        ]


class BookModelSerializer(serializers.ModelSerializer):
    # 一种方案(只序列化可以,反序列化有问题)
    # publish=serializers.CharField(source='publish.name')
    # 第二种方案,models中写方法

    class Meta:
        list_serializer_class=BookListSerializer  # 设置 自定义序列化器的列表类  默认是ListSerializer
        model=models.Book
        # fields='__all__'
        # depth=0   # 用的少
        fields = ('name','price','authors','publish','publish_name','author_list')

        extra_kwargs={
            'publish':{'write_only':True},
            'publish_name':{'read_only':True},
            'authors':{'write_only':True},
            'author_list':{'read_only':True}
        }
# models.py
from django.db import models

# 一般情况下:一个表中若写了id字段,那所有表都会写;要嘛,全都不写
	
from django.contrib.auth.models import AbstractUser
class BaseModel(models.Model):
    # 删除(用字段标记,不会真正的删除数据)  
    # 使用choices参数:二维的二元元组,第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体内容
    # 获取显示的内容:get_字段名_display()
    delete_choices = ((False, '未删除'), (True, '已删除'))
    is_delete = models.BooleanField(choices=delete_choices, default=False) 
    # 布尔类型,实质在数据库表中 存放就是数据类型的 0和1 
    
    # 创建时间:
    # 方式一:auto_now_add=True 创建记录时,自动把当前时间插入,后续不会改变(不需要手动插入时间)
    create_time=models.DateTimeField(auto_now_add=True)
    # 方式二:写默认值 (注意有坑:datetime.now不能加括号调用,因为加括号调用后,就是固定的时间数据--项目的执行时间)
    import datetime
    create_time=models.DateTimeField(default=datetime.datetime.now)
    
    # 更新时间
    # auto_now=True, 每次更新时,就会把当前时间插入
    last_update_time=models.DateTimeField(auto_now=True) 
    
    class Meta:
        # Meta可以控制(就是给当前类设定一些属性,当前类 通过orm 又对应数据库的表):
        # 1.在admin中 将表名显示为自定义的名字 (原理:跟字段写verbose_name一样,设置当前类的别名)
        # 复数形式,如果只设置verbose_name,在Admin会显示为“表名s”
        verbose_name = '表名' 
        verbose_name_plural = "表名"
        
		# 2.控制该表联合属性 (数据库中:单个字段,有索引,有唯一; 多个字段,有联合索引,联合唯一)
        index_together=[]  # 联合索引
        unique_together=[]  # 联合唯一
        
        # 3.设置当前类为抽象类
        abstract=True  # 抽象类/模型类,表示该类只能用于继承,不会有实例化对象 (此处就是不在数据库建立出真正的表)

        
class Book(BaseModel):
    id=models.AutoField(primary_key=True)
    # verbose_name admin中会显示该别名
    name=models.CharField(max_length=32,verbose_name='书名',help_text='这里填书名')
    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)
    class Meta:
        verbose_name_plural='书表'  # admin中表名的显示

    def __str__(self):
        return self.name

    @property
    def publish_name(self):
        return self.publish.name
    
    def author_list(self):
        author_list=self.authors.all()
        # ll=[]
        # for author in author_list:
        #     ll.append({'name':author.name,'sex':author.get_sex_display()})
        # return ll
        return [ {'name':author.name,'sex':author.get_sex_display()}for author in author_list]

class Publish(BaseModel):
    name = models.CharField(max_length=32)
    addr=models.CharField(max_length=32)
    
    def __str__(self):
        return self.name


class Author(BaseModel):
    name=models.CharField(max_length=32)
    sex=models.IntegerField(choices=((1,'男'),(2,'女')))
    # 一对一关系,写在查询频率高的一方
    # OneToOneField本质就是ForeignKey+unique,自己手写也可以
    authordetail=models.OneToOneField(to='AuthorDetail',db_constraint=False,on_delete=models.CASCADE)

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

# 二、表断关联
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

2.books系列表接口--me

# url.py

from django.urls import path
from app01 import views

urlpatterns = [
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookView.as_view())
]
# view.py

from django.shortcuts import render, HttpResponse
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView
from rest_framework.response import Response

from app01.serializer import BookModelSerializer
from app01.models import Book


class BookView(ListCreateAPIView, RetrieveUpdateAPIView):
    serializer_class = BookModelSerializer
    queryset = Book.objects.filter(is_delete=False).all()

    def get(self, request, *args, **kwargs):
        # 通过url的转化器(有名分组路由匹配数字给pk), 若有pk值,执行单查
        if kwargs.get('pk'):
            return self.retrieve(request, *args, **kwargs)
        # 没有pk值,执行多查
        else:
            return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        # 单增,直接调用 父类的create()
        if isinstance(request.data, dict):
            return self.create(request, *args, **kwargs)
        # 多增,则是调用 ListSerializer的save() 保存
        elif isinstance(request.data, list):
            serializer = self.get_serializer(data=request.data, many=True)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(data=serializer.data)

    def put(self, request, *args, **kwargs):
        # 单改
        if kwargs.get('pk'):
            return self.update(request, *args, **kwargs)
        # 多改 (重写ListSerializer的update方法)
        # 前端传递数据格式[{id:1,name:xx,price:xx},{id:1,name:xx,price:xx}]
        # 处理传入的数据  对象列表[book1,book2]  修改的数据列表[{name:xx,price:xx},{name:xx,price:xx}]
        else:
            book_list = []
            modify_data = []
            for item in request.data:
                pk = item.pop('id')
                book_obj = self.queryset.filter(pk=pk).first()
                book_list.append(book_obj)
                modify_data.append(item)
            book_ser = BookModelSerializer(instance=book_list, data=modify_data, many=True)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(book_ser.data)

    def delete(self, request, *args, **kwargs):
        # 统一采用多条删除的方式
        pk = kwargs.get('pk')
        pks = []
        if pk:
            pks.append(pk)
        else:
            pks = request.data.get('pks')
            print(pks)
        res = Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
        if not res:
            return Response(data={'code': 101, 'msg': '删除失败'})
        return Response(data={'code': 100, 'msg': f'成功删除{res}条数据'})
# models.py


from django.db import models


class BaseModel(models.Model):
    delete_choices = ((False, '未删除'), (True, '已删除'))
    is_delete = models.BooleanField(choices=delete_choices, default=False, verbose_name='是否删除')
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    last_update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        abstract = True


class Book(BaseModel):
    name = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='价格')

    publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False)
    authors = models.ManyToManyField(to='Author', db_constraint=False)

    @property
    def authors_list(self):
        authors = self.authors.all()
        return [author.name for author in authors]

    class Meta:
        verbose_name_plural = '图书表'

    def __str__(self):
        return self.name


class Publish(BaseModel):
    name = models.CharField(max_length=32, verbose_name='名字')
    address = models.CharField(max_length=32, verbose_name='地址')

    class Meta:
        verbose_name_plural = '出版社表'

    def __str__(self):
        return self.name


class Author(BaseModel):
    name = models.CharField(max_length=32, verbose_name='名字')
    sex = models.IntegerField(choices=((1, '男'), (2, '女')), null=True, verbose_name='性别')
    author_detail = models.OneToOneField(to='AuthorDetail', db_constraint=False,
                                         on_delete=models.CASCADE, verbose_name='作者详情')

    class Meta:
        verbose_name_plural = '作者表'

    def __str__(self):
        return self.name


class AuthorDetail(BaseModel):
    phone = models.CharField(max_length=11, verbose_name='电话')

    class Meta:
        verbose_name_plural = '作者详情表'

    def __str__(self):
        return self.phone
# serializer.py

from rest_framework import serializers
from app01.models import Book


class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        return [
            self.child.update(instance=instance[i], validated_data=attrs) for i, attrs in enumerate(validated_data)
        ]


class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        list_serializer_class = BookListSerializer
        model = Book
        fields = ['name', 'price', 'publish', 'publish_name', 'authors', 'authors_list']

        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {'read_only': True},
            'authors': {'write_only': True},
            'author_list': {'read_only': True}
        }

    publish_name = serializers.SerializerMethodField()
    def get_publish_name(self, instance):
        return instance.publish.name

作业

# 1 一个表可不可以有多个自增字段
不可以,猜测:因为若是有多个自增字段(默认就不会为空了),那么就相当于有多个主键
posted @ 2021-12-20 01:01  Edmond辉仔  阅读(101)  评论(0编辑  收藏  举报