一、二次封装Resonse
responses.py
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self, status=None, msg=None, http_status=None, *args, **kwargs):
data = {
'status': status,
'msg': msg,
}
if kwargs:
data.update(kwargs)
super().__init__(status=http_status,data=data)
二、数据库关系分析
'''
1.相互有关系的两张表,增删改操作会相互影响,导致效率低下,查询操作就是正常的连表操作
2.相互有关的两张表,断开外键关系,但从代码逻辑层面保持原来的联系
- 这样一来,每个表都可以单独操作,提高了增删改查的效率,在开发中要避免由此带来的脏数据,事务 + 代码层面的逻辑约束
- 由于数据没有发生变化,查询的连表操作不会受到影响
3. django的orm支持断关联操作关系表,且所有的操作方式和没有断开关联的操作是一致的(在django2.0以上默认不进行级联更新)
'''
三、orm操作关系
'''
外键位置:
1.一对多的外键关系,FK毫无疑问建立在多的乙方,如书与出版社,外键应该放在书表中。
2.多对多的外键关系,ManyToManyField放在任一一端都可以,因为会创建第三章关系表,在关系表中用两个外键分别关联两个表
3.一多一的的外键关系,OneToOneField放在依赖的表,如作者与作者详情表,作者详情依赖于作者,所以将其放在作者详情表。
OneToOneField会被转换为外键+ 位移约束。
'''
'''
ORM关系Field:
ForeignKey可以设置related_name, db_constraint, on_delete
OneToOneField可以设置related_name, db_constraint, on_delete
ManyToManyField只能设置related_name, db_constraint
- 不能设置on_delete的原因:无论放在A表还是B表,第三张表都会受到影响。
- 可以自定义关系表,在关系表的两个外键分别设置on_delete
'''
'''
各参数的含义:
related_name:表之间反向访问的名字,默认是表名小写|表名小写_set
db_constraint:表之间的关联关系,默认为True为关联。设置为False,可以提高增删改查的效率,且不影响其他操作
on_delete:在django 1.x下默认是CASCADE,在django 2.x中需要手动。
'''
'''
表关系:
作者详情依赖于作者,作者被删除跟着被删除:CASCADE
作者与书的关系,当作者被删除,书不变:DO_NOTHING
部门表与员工表,一条部门记录被删除时,
部门内的员工全部进入未分组部门:SET_DEFAULT(需要配合default属性使用)
或
部门内的员工外键字段设置为空:SET_NULL(需要配合null=True属性使用)
'''
案例测试
import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day69.settings")
django.setup()
from api.models import Author, AuthorDetail
# print(Author.objects.all())
# print(AuthorDetail.objects.all())
#
# AuthorDetail.objects.first().delete() # type Author
#
# print(Author.objects.all())
# print(AuthorDetail.objects.all())
obj = Author.objects.first()
print(obj.name,obj.detail.phone)
d_obj = AuthorDetail.objects.first()
print(d_obj.phone,d_obj.author.name)
四、基表
# 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的
class BaseModel(models.Model):
is_delete = models.BooleanField(default=False)
updated_time = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True # 必须完成该配置
继承基表
class Book(BaseModel):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
image = models.ImageField(upload_to='img', default='img/default.png')
publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
class Publish(BaseModel):
name = models.CharField(max_length=64)
class Author(BaseModel):
name = models.CharField(max_length=64)
class AuthorDetail(BaseModel):
phone = models.CharField(max_length=11)
author = models.OneToOneField(
to=Author,
related_name='detail',
db_constraint=False,
on_delete=models.SET_NULL,
null=True
)
五、序列化类的其他配置(了解)
class AuthorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
# 不常用,将全部字段提供给外界
fields = '__all__'
# ------------------------------------------------------------------
class AuthorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
# 不常用,排除指定字段的其他所有字段,不能自动包含 外键反向 字段
exclude = ['is_delete', 'updated_time']
# ------------------------------------------------------------------
class AuthorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
# 'detail', 'books' 是 外键(正向|反向) 字段
fields = ['name', 'detail', 'books']
# 不常用,自动深度,自动深度会显示外键关联表的所有字段
depth = 2
# 正向外键字段:就是外键的属性名
# 反向外键字段:就是外键属性设置的related_name
六、子序列化
'''
1.子序列化的字段,必须是外键(正向或反向)字段
2.子序列化对应的数据单个many=False,多个对应many=True
3.子序列化其实就是自定义序列化字段,覆盖了原有外键字段的规则,所以不能进行反序列化********
'''
案例
serializers.py
from rest_framework import serializers
from . import models
class AuthorDetailModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.AuthorDetail
fields = ['phone']
# 子序列化detail字段
class AuthorModelSerializer(serializers.ModelSerializer):
detail = AuthorDetailModelSerializer(many=False)
class Meta:
model = models.Author
fields = ['name','detail']
# 子序列化author字段
class BookModelSerializer(serializers.ModelSerializer):
author = AuthorModelSerializer(many=True)
class Meta:
model = models.Book
# fields = ['name', 'price']
# fields = '__all__'
# exclude = ['is_delete','create_time']
# depth = 1
fields = ['name', 'price', 'author']
七、多表序列化与反序列化
'''
1.外键字段要参与反序列化,所以外键字段设置为write_only
2.外键关系需要联表序列化结果(而不是仅返回外键字段的id),可以在model中自定义@property来自定义联表序列化
'''
完成反序列化仅仅需要将外键字段在fields中声明即可
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
# author和publish都为外键字段
fields = ['name', 'price', 'author','publish']
# 请求数据格式----drf能自动识别需要接受的类型如[]
{
"name":"西游记1",
"price":"6.66",
"author":[2,3],
"publish":1
}
序列化数据:由于将外键字段留给了反序列化使用,需要在model类中定义@property属性(默认只参与序列化)同时设置原来的外键字段write_only
serializers.py
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
# author和publish都为外键字段
fields = ['name', 'price', 'author','publish','publish_name','author_list']
extra_kwargs = {
'author':{
'write_only':True
},
'publish': {
'write_only': True
}
}
models.py
class Book(BaseModel):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=8, decimal_places=2)
publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
author = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
@property
def publish_name(self):
return self.publish.name
'''方式一
@property
def read_author_list(self):
a_list = []
for author_obj in self.author.all():
info_dict = {}
info_dict['name'] = author_obj.name
# detail字段可能为空
try:
info_dict['phone'] = author_obj.detail.phone
except:
info_dict['phone'] = ''
a_list.append(info_dict)
return a_list
'''
# 方式二:需要辅助类
@property
def author_list(self):
from .serializers import AuthorModelSerializer
return AuthorModelSerializer(self.author.all(),many=True).data
views.py
from rest_framework.views import APIView
from . import models
from . import serializers
from .responses import APIResponse
from rest_framework import status
# 六个必备接口:单查(✔)、群查(✔)、单增(✔)、单删、单整体改(了解)、单局部改
# 四个额外接口:群增(✔)、群删、群整体改、群局部改
class BookAPIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
if obj:
serializer = serializers.BookModelSerializer(obj, many=False)
return APIResponse(status=0, msg='ok', result=serializer.data, http_status=200)
else:
return APIResponse(status=0, msg='data not exists')
else:
objs = models.Book.objects.all()
serializer = serializers.BookModelSerializer(objs, many=True)
return APIResponse(status=0, msg='ok', result=serializer.data, http_status=200)
def post(self, request, *args, **kwargs):
data = request.data
# 是否多个数据进行判断
# 单增
if not isinstance(data, list):
serializer = serializers.BookModelSerializer(data=data)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
return APIResponse(status=0, msg='ok', result=serializers.BookModelSerializer(obj, many=False).data,
http_status=201)
# 群增
else:
serializer = serializers.BookModelSerializer(data=data,many=True)
serializer.is_valid(raise_exception=True)
objs = serializer.save()
# 将objs重新序列化返回给前端(序列化与反序列化信息不对等)
return APIResponse(status=0,msg='ok',result=serializers.BookModelSerializer(objs,many=True).data,http_status=status.HTTP_201_CREATED)
# 友情注释:群增其实是借助了ListSerializer来的create方法完成的
小结
"""
1)二次封装Response:
自定义类继承Response,重写init方法,在内部格式化data
2)表关系分析:
断关联:
优点:提示增删改操作效率,不允许查效率
缺点:增删改操作可能会导致脏数据,所以需要通过逻辑或是事务来保证
3)ORM表关系处理语法:
1)外键所在位置
2)如何断关联db_constraint
3)正向方向自定义名字:related_name
4)表关系:on_delete四种
4)基表:Meta中配置abstract=True,来被继承,提供共有字段
5)多表连表Meta中的了解配置
fields = '__all__' # 不常用,将全部字段提供给外键
exclude = ['is_delete', 'updated_time'] # 不常用,排除指定字段的其他所有字段
depth = 2 # 不常用,主动深度,自动深度会显示关联表的所有字段
6)子序列化
i)通常只用于序列化过程,对外键字段进行了覆盖,影响外键字段的反序列化过程
class SubSerializer:
pass
class SupSerializer:
外键 = SubSerializer(many=True|False)
7)多表的序列化与反序列化
1)连表序列化用自定义@property完成:内部实现可以自定义逻辑,也可以走序列化类
2)外键字段留给反序列化来使用
8)单查、群查、单增、群增接口
"""