books系列表接口
总路由/urls.py
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api.urls')), ]
api/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()), ]
models.py
Meta中abstract这个属性是定义当前的模型类是不是一个抽象类。所谓抽象类是不会对应数据库表的。一般我们用它来归纳一些公共属性字段,然后继承它的子类可以继承这些字段
from django.db import models # Create your models here. class BaseModel(models.Model): is_delete = models.BooleanField(default=False) # auto_now_add=True 只要记录创建,不需要手动插入时间,自动把当前时间插入 create_time = models.DateTimeField(auto_now_add=True) # auto_now=True,只要更新,就会把当前时间插入 last_update_time = models.DateTimeField(auto_now=True) # import datetime # create_time=models.DateTimeField(default=datetime.datetime.now()) # 这是个坑,因为加括号以后所有时间都是项目运行的时间
# create_time=models.DateTimeField(default=datetime.datetime.now) # 如果要用这样用 class Meta: # 单个字段,有索引,有唯一 # 多个字段,有联合索引,联合唯一 abstract = True # 抽象表,不在数据库建立出表 class Book(BaseModel): # verbose_name admin中显示中文 name = models.CharField(max_length=32, verbose_name='书名', help_text='这里填书名') price = models.DecimalField(max_digits=8, decimal_places=2) # 一对多的关系一旦确立,关联字段写在多的一方,
# to 指名关联的表 # 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): 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
ser.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) def update(self, instance, validated_data): print(instance,type(instance[0])) print(validated_data) """ [<Book: 物联网>, <Book: 武庚纪>] <class 'api.models.Book'> [
{'name': '物联网', 'price': Decimal('66.00'), 'authors': [<Author: Author object (1)>, <Author: Author object (2)>], 'publish': <Publish: 南京出版社>},
{'name': '武庚纪', 'price': Decimal('23.00'), 'authors': [<Author: Author object (1)>], 'publish': <Publish: 东郊出版社>}
] """ # 保存数据 # self.child:是BookModelSerializer对象 # ll=[] # for i,si_data in enumerate(validated_data): # ret=self.child.update(instance[i],si_data) # ll.append(ret) # return ll return [ # self.child.update(对象,字典) for attrs in validated_data self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data) ] # 如果序列化的是数据库的表,尽量用ModelSerializer class BookModelSerializer(serializers.ModelSerializer): # publish,显示出版社名称 # 一种方案(只序列化可以,反序列化有问题) # publish=serializers.CharField(source='publish.name') # 第二种方案,models中写方法(看models.py) class Meta: list_serializer_class = BookListSerializer model = models.Book # fields='__all__' # 用的少 # depth=0 fields = ('id', '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} }
补充:序列化中depth说明
https://blog.csdn.net/study_in/article/details/88885869
views.py
from django.shortcuts import render # Create your views here. 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): #查询单个和查询所有,合到一起 if not 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) #查一个 book_list = models.Book.objects.filter(pk=kwargs.get('pk')).first() book_list_ser = BookModelSerializer(book_list) 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 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() book_ser = BookModelSerializer(instance=book, data=request.data, partial=True) # 增多条 # partial=True # partial 表示是否可以部分修改 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) # request.data # # book_ser=BookModelSerializer(data=request.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': '没有要删除的数据'})
补充:
如果是使用GenericAPIView实现单条和多条在一个视图
settings.py 注册
'rest_framework',
总路由/urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api.urls')), ]
api/urls.py
from django.urls import path, re_path from api import views urlpatterns = [ path('books/', views.BookView.as_view()), re_path('books/(?P<pk>\d+)', views.BookView.as_view()), ]
models.py
from django.db import models # Create your models here. class BaseModel(models.Model): is_delete = models.BooleanField(default=False) # auto_now_add=True 只要记录创建,不需要手动插入时间,自动把当前时间插入 create_time = models.DateTimeField(auto_now_add=True) # auto_now=True,只要更新,就会把当前时间插入 last_update_time = models.DateTimeField(auto_now=True) # import datetime # create_time=models.DateTimeField(default=datetime.datetime.now) class Meta: # 单个字段,有索引,有唯一 # 多个字段,有联合索引,联合唯一 abstract = True # 抽象表,不在数据库建立出表 class Book(BaseModel): # verbose_name admin中显示中文 name = models.CharField(max_length=32, verbose_name='书名', help_text='这里填书名') price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格') # 一对多的关系一旦确立,关联字段写在多的一方 # to_field 默认不写,关联到Publish主键 # db_constraint=False 逻辑上的关联,实质上没有外键练习,增删不会受外键影响,但是orm查询不影响 publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='出版社') # 多对多,跟作者,关联字段写在 查询次数多的一方 # 什么时候用自动,什么时候用手动?第三张表只有关联字段,用自动 第三张表有扩展字段,需要手动写 # 不能写on_delete authors = models.ManyToManyField(to='Author', db_constraint=False, verbose_name='作者') 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): 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, verbose_name='出版社名称') addr = 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, '女')), verbose_name='性别') # 一对一关系,写在查询频率高的一方 # OneToOneField本质就是ForeignKey+unique,自己手写也可以 authordetail = models.OneToOneField(to='AuthorDetail', db_constraint=False, on_delete=models.CASCADE, verbose_name='作者详情') def __str__(self): return self.name class Meta: verbose_name_plural = '作者表' class AuthorDetail(BaseModel): mobile = models.CharField(max_length=11, verbose_name='手机号') class Meta: verbose_name_plural = '作者详情表'
ser.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) ## 批量改 def update(self, instance, validated_data): print(instance, type(instance[0])) print(validated_data) """ [<Book: 物联网>, <Book: 武庚纪>] <class 'api.models.Book'> [ {'name': '物联网', 'price': Decimal('66.00'), 'authors': [<Author: Author object (1)>, <Author: Author object (2)>], 'publish': <Publish: 南京出版社>}, {'name': '武庚纪', 'price': Decimal('23.00'), 'authors': [<Author: Author object (1)>], 'publish': <Publish: 东郊出版社>} ] """ # 保存数据 # self.child:是BookModelSerializer对象 # ll=[] # for i,si_data in enumerate(validated_data): # ret=self.child.update(instance[i],si_data) # ll.append(ret) # return ll return [ # self.child.update(对象,字典) for attrs in validated_data self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data) ] # 如果序列化的是数据库的表,尽量用ModelSerializer class BookModelSerializer(serializers.ModelSerializer): # publish,显示出版社名称 # 一种方案(只序列化可以,反序列化有问题) # publish=serializers.CharField(source='publish.name') # 第二种方案,models中写方法(看models.py) class Meta: list_serializer_class = BookListSerializer # 批量改, model = models.Book # fields = '__all__' # 用的少 depth = 0 fields = ('id', '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} }
views.py
from django.shortcuts import render from rest_framework.generics import GenericAPIView from .models import Book from .ser import BookModelSerializer from utils.response import MyResponse from api import models # Create your views here. class BookView(GenericAPIView): queryset = Book.objects.all().filter(is_delete=False) serializer_class = BookModelSerializer def get(self, request, *args, **kwargs): # 查询单个和查询所有,合到一起 if not kwargs: # 查所有 book_list = self.get_queryset() serializer = self.get_serializer(book_list, many=True) return MyResponse(200, "获取成功", result=serializer.data) # 查一个 book = self.get_object() book_ser = self.get_serializer(book) return MyResponse(200, "获取成功", result=book_ser.data) def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) # 具备增单条,和增多条的功能 ''' 单条: { "name": "武庚纪", "price": 45.12, "authors": [1,2], "publish": 1 } 多条: [ { "name": "追风筝的少年", "price": 15.12, "authors": [ 1 ], "publish": 2 }, { "name": "三国演义", "price": 33.12, "authors": [ 1 ], "publish": 1 } ] ''' if isinstance(request.data, dict): if serializer.is_valid(): serializer.save() return MyResponse(200, "创建成功", result=serializer.data) else: return MyResponse(101, '添加失败') elif isinstance(request.data, list): # 现在book_ser是ListSerializer对象 # <class 'rest_framework.serializers.ListSerializer'> book_ser = BookModelSerializer(data=request.data, many=True) # 增多条 print('--------', type(book_ser)) book_ser.is_valid(raise_exception=True) book_ser.save() return MyResponse(200, "创建成功", result=book_ser.data) def put(self, request, *args, **kwargs): # 改一个,改多个 # 改一个 if kwargs.get('pk', None): book = self.get_object() book_ser = self.get_serializer(instance=book, data=request.data, partial=True) # partial=True # partial 表示是否可以部分修改 if book_ser.is_valid(): book_ser.save() return MyResponse(200, "修改成功", result=book_ser.data) else: return MyResponse(101, "修改失败", result={'status': 101, 'msg': '校验失败'}) else: # 改多个, # put http://127.0.0.1:8000/api/books/ # 前端传递数据格式[{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: 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 = self.get_serializer(instance=book_list[i], data=si_data) book_ser.is_valid(raise_exception=True) book_ser.save() return MyResponse(200, "修改成功") ''' # 第二种方案,重写ListSerializer的update方法 book_ser = self.get_serializer(instance=book_list, data=modify_data, many=True) book_ser.is_valid(raise_exception=True) book_ser.save() # ListSerializer的update方法,自己写的update方法 # BookModelSerializer中Meta的list_serializer_class和自己写的ListSerializer做关联 return MyResponse(200, "修改成功") 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 MyResponse(200, "删除成功") else: return MyResponse(101, "没有要删除的数据")
postman测试
单查,多查
单增、多增
单改、部分改、多改
partial=True 部分改
单删、多删