一、二次封装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)单查、群查、单增、群增接口 """
来源:https://www.cnblogs.com/Ghostant/p/12348054.html