一、代码部分
总路由/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')),
]
总路由/urls.py
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 部分改
单删、多删
文档更新时间: 2022-07-15 09:57 作者:李延召