drf图书管理数据的增删查改

模型类

from django.db import models

# Create your models here.

class BaseModel(models.Model):
    create_time = models.DateTimeField(auto_now_add=True)
    is_delete = models.BooleanField(default=False)
    last_update_time = models.DateTimeField(auto_now=True)

    class Meta:
        # abstract=True说明是一个抽象类,不会生成表
        abstract = True


class Book(BaseModel):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5,decimal_places=2)
    # db_constraint表示实质上没有外键联系,只是逻辑上的关联,增删不会有影响,同时不影响我们orm查询
    publish = models.ForeignKey(to='Publish',db_constraint=False,on_delete=models.DO_NOTHING)
    # 自动:中间表只有两个表的关联字段,用自动创第三张表的方式
    # 手动:中间表有扩展字段,需要用手动的方式,through,through_fields,
    authors = models.ManyToManyField(to='Author')
    class Meta:
        verbose_name_plural = '图书表'

    # common_serializer.py中的方案二
    @property
    def publish_name(self):
        return self.publish.name

    # # 也可以用common_serializers.py中的方案三
    # def author_list(self):
    #     author_list = self.authors.all()
    #     # 可以用列表生成式代替下面代码块
    #     # l = []
    #     # for author in author_list:
    #     #     l.append({'name':author.name,'gender':author.get_gender_display()})
    #     # return l
    #     return [{'name':author.name,'gender':author.get_gender_display()} for author in author_list]

    def __str__(self):
        return '%s'% self.name


class Publish(BaseModel):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=255)
    class Meta:
        verbose_name_plural = '出版社表'

    def __str__(self):
        return '%s'% self.name


class Author(BaseModel):
    name = models.CharField(max_length=32)
    gender = models.IntegerField(choices=((1,''),
                                          (2,'')),
                                 )
    # OneToOneField本质就是ForeignKey+unique,自己手动写也可以
    author_detail = models.OneToOneField(to='AuthorDetail',db_constraint=False,on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = '作者表'

    def __str__(self):
        return '%s'% self.name


class AuthorDetail(BaseModel):
    phone = models.CharField(max_length=32)

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

序列化器

# common_serializer.py

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)

    # 重写update方法
    def update(self, instance, validated_data):
        print(instance)
        print(validated_data)
        # 保存数据
        # self.child:是BookModelSerializer对象
        # 下面的代码块可以用列表生成式表示
        # l = []
        # for i,attrs in enumerate(validated_data):
        #     res = self.child.update(instance[i],attrs)
        #     l.append(res)
        # return l
        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的id还是name)
    # publish = serializers.CharField(source='publish.name')
    # 方案三(跟方案二差不多,方案二在模型类中定义方法,方案三直接在序列化器内定义方法)
    # authors = serializers.SerializerMethodField()
    # # 方案三配套方法,方法名:get_字段名
    # def get_authors(self, instance):
    #     authors = instance.authors.all()  # 这里的instance就是模型类中的book对象
    #     l = []
    #     for author in authors:
    #         l.append({'name':author.name,'gender':author.get_gender_display()})
    #     return l

    class Meta:
        # 通过list_serializer_class与BookListSerializer类进行关联
        list_serializer_class = BookListSerializer
        model = models.Book
        # 方案二(在模型类中定义一个publish_name方法),推荐
        # fields = ('name','price','publish','publish_name','authors','author_list')
        fields = ('name','price','publish','publish_name','authors',)
        # depth = 1  # 可以设置深度,查询联表下一级的数据
        extra_kwargs = {
            'publish':{"write_only":True},
            'publishj_name':{'read_only':True},
            # 'authors': {"write_only": True},
            # 'author_list': {'read_only': True},
        }
    # publish = serializers.SerializerMethodField()
    # def get_publish(self, instance):
    #     publish_name = instance.publish.name
    #     return publish_name

视图函数

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from api import models
from api.common_serializers import BookModelSerializer

# Create your views here.

class BookGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.all().filter(is_delete=False)
    serializer_class = BookModelSerializer

    def get(self,request,*args,**kwargs):
        books = self.get_queryset()
        # 查询多条 需要加many=True
        book_ser = self.get_serializer(instance=books,many=True)
        return Response(book_ser.data)

    def post(self,request,*args,**kwargs):
        # 如果传的数据是字典 说明是增1条
        if isinstance(request.data,dict):
            book_ser = self.get_serializer(data=request.data)
            if book_ser.is_valid():
                book_ser.save()
                return Response(book_ser.data)
        # 如果传的数据是列表 说明是增多条
        elif isinstance(request.data,list):
            # 新增多条 需要加many=True
            book_ser = self.get_serializer(data=request.data,many=True)
            if book_ser.is_valid():
                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(book_ser.data)

    def put(self,request,*args,**kwargs):
        # 改单个 判断是否有pk 如果有则修改单个 没有则修改多个
        if kwargs.get('pk',None):
            book = self.get_object()
            # partial=True表示可以修改部分内容
            book_ser = self.get_serializer(instance=book,data=request.data,partial=True)
            if book_ser.is_valid():
                book_ser.save()
                return Response(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_list = []
        #     # 方式一:直接通过for循环前端传过来的数据,对数据进行不同的处理
        #     for book_dic in request.data:
        #         pk = book_dic.pop('id',None)  # 获取id 通过id获取book对象
        #         book = models.Book.objects.filter(pk=pk).first()
        #         book_list.append(book)  # 得到[book1,book2]
        #         modify_data_list.append(book_dic)  # 删除id后的book_dic [{name:xx,price:xx},{name:xx,price:xx}]
              # 通过for循环一条条修改
        #     for i,modify_data in enumerate(modify_data_list):
        #         book_ser = self.get_serializer(instance=book_list[i],data=modify_data)
        #         if book_ser.is_valid():
        #             book_ser.save()
        #     return Response({'msg':'修改成功%s条数据'%(i+1)})

            # 方式二:在序列化器的py文件内 重写ListSerializer类中的update方法 本质也是通过for循环
            book_list = []
            modify_data_list = []
            for book_dic in request.data:
                pk = book_dic.pop('id',None)
                book = models.Book.objects.filter(pk=pk).first()
                book_list.append(book)
                modify_data_list.append(book_dic)  # 删除id后的book_dic
            # 直接传入对象列表[book1,book2] 以及修改的数据列表[{name:xx,price:xx},{name:xx,price:xx}]
            # 修改多条必须加many=True 会直接走ListSerializer
            book_ser = self.get_serializer(instance=book_list,data=modify_data_list,many=True)
            if book_ser.is_valid():
                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里面删
            pks.append(pk)
        else:
            # 多条删除 {'pks':[1,2,3]}
            pks = request.data.get('pks')
        # 把is_delete设置成True res返回的是受影响的行数
        res = models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True)
        if res:
            return Response({'msg':'删除成功!删除了%s行'%res})
        else:
            return Response({'msg':'没有你要删除的数据'})

路由

from django.contrib import admin
from django.urls import path,re_path
from api import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/',views.BookGenericAPIView.as_view()),
    re_path(r'^books/(?P<pk>\d+)/',views.BookGenericAPIView.as_view()),  # 匹配带pk的视图
]

 

posted @ 2022-05-20 20:42  _yessir  阅读(139)  评论(0编辑  收藏  举报