drf-ModelSerializer的使用、请求与响应
补充:django项目改名字后顺利运行
1 先改文件夹名
2 改项目名
3 改 项目内的文件夹名
4 替换掉所有文件中的 drf_day04 ---》drf_day05
5 命令行中启动:python manage.py runserver
6 setting--->django--->指定项目根路径
一、ModelSerializer的使用
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer继承了Serializer,它可以直接跟表模型建立关系
- 1. 要序列化或者反序列化的字段,不需要我们自己写了,直接从表模型中映射过来
- 2. 封装了 create 和update方法,但是后期可能自己还是要重写这两个方法的
Serializer.py文件中(序列化类):
from rest_framework import serializers from .models import Book class BookSerializer(serializers.Serializer): """序列化的时候: 1. 有的字段不想做序列化 2. publish 默认显示id,我们想显示详情--->重写字段,必须在fields中注册 3. 作者显示id列表,我们想显示作者详情列表--->重写字段,必须在fields中注册 """ class Meta: model = Book # fields = '__all__'# 内部本质:把Book表模型中所有字段,都复制过来的 fields = ['name', 'price', 'publish_dict', 'author_list', 'publish', 'authors'] # 表中没有的字段也必须要在fields中注册 # extra_kwrags:给字段增加属性 extra_kwrags = { 'name': {'max_length': 8, 'min_length': 3}, # 相当于:name=serializers.CharField(max_length=8,min_length=3) 'publish': {'write_only': True}, # 只反序列化 ,只写models表中的字段,不能写成:publish_id 'authors': {'write_only': True} # 只反序列化 } # 自己定制的字段,做序列化返回给前端 publish_dict = serializers.DictField(read_only=True) author_list = serializers.ListField(read_only=True) # 局部钩子和之前的一样写,单个字段校验 def validate_price(self, value): pass # 全局钩子,和之前的一样写,多个字段同时校验 def validate(self, attrs): pass
Views.py中:
from rest_framework.views import APIView from rest_framework.response import Response from .models import Book from .serializer import BookSerializer class BookView(APIView): def get(self, request,*args,**kwargs): # 查询所有的数据 books = Book.objects.all() ser = BookSerializer(instance=books, many=True) return Response({'code': 100, 'msg': '查询成功', 'result': ser.data})
models中:
from django.db import models class Book(models.Model): name = models.CharField(max_length=32,unique=True) price = models.IntegerField() publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) # 多对多关系---》 # authors 写了这个字段,在数据的book表中,不会有这个字段,而它的形式是 一个中间表 authors = models.ManyToManyField(to='Author') @property def publish_dict(self): return {'name': self.publish.name, 'addr': self.publish.addr} @property def get_name(self): return self.name + '-NB' def author_list(self): l = [] for author in self.authors.all(): l.append({'name': author.name, 'sex': author.sex, 'age': author.age}) return l
结果如图:
二、 模块与包的使用(很重要)
模块与包
-模块:一个py文件,被别的py文件导入使用,这个py文件称之为模块,运行的这个py文件称之为脚本文件
- s1能够自己点右键运行,这个文件s1叫脚本文件
比如:
- 在s2中,把s1,引入使用,s1就叫模块
比如:
-包:一个文件夹下有__init__.py
-作用:包内部的函数,类..想给外部方便使用(导入的时候路径短一些),就要在里面做注册
比如:
模块与包的导入问题
''' 0. 导入模块有相对导入和绝对导入,绝对的路径是从环境变量开始的
1. 导入任何模块,如果使用绝对导入,都是从环境变量开始导入起
import xx #### xx所在路径必须在环境变量
from yy import ####yy所在路径必须在环境变量中
2. 脚本文件执行的路径,会自动加入环境变量
3. 相对导入的话,是从当前py文件开始计算的
4. 以脚本运行的文件,不能使用相对导入,只能用绝对导入
'''
三、反序列化校验源码分析
之前---》ser.is_valid()--->三层---》局部钩子和全局钩子写法是固定---》源码中规定了是要这么写---》如果不这么写,它就执行不了
入口:is_valid()
首先会先去找BookSerializer中的is_valid方法,没有会去继承的父类Serializer中去找,也没有,就继续往上找,在Serializer继承的父类:BaseSerializer中找到了is_valid()方法,
分析is_valid方法源码:
-核心:self._validated_data = self.run_validation(self.initial_data)
-self是谁?序列化类的对象--》BookSerializer---》应该从根上找:BookSerializer,然后一层一层往上走,最后在Serializer类中找到了run_validation方法
然后在执行了:self.to_internal_value(data)
查找顺序:
总结:
只要执行序列化类对象的.is_valid就会执行 BaseSerializer的is_valid---》就会执行:self._validated_data = self.run_validation(self.initial_data)----》Serializer的run_validation---》两句重要的话:value = self.to_internal_value(data);value = self.validate(value)---》这两句话就是局部钩子和全局钩子---》局部钩子再进去看到了validate_字段名
四、断言
assert 关键字,断定这个条件是符合的,才能往下走,如果不符合,就抛异常
断言小案例:
# 断言 name = '彭于晏' # assert name == 'lqz', '不是lqz,不能执行了' # 用代码翻译:翻译这句话 if not name=='lqz': raise Exception("不是lqz,不能执行了") print('lqz,来了老弟')
五、drf之请求
请求指的就是新的request对象
请求源码分析:
from rest_framework.request import Request:从这边点进去看request
1 以后视图类的方法中的request都是这个类的对象
2 以后使用request.data 取请求体中的数据
3 以后使用request.query_params 取请参数中的数据
4 以后其他属性,用起来跟之前一样---》重要
-request.method 的时候---》实际上 request._request.'method'---》反射出来的
-这个类from rest_framework.request import Request没有method,他会触发这个类的__getattr__---》
5 FILES 用起来跟之前一样,前端传入的文件在里面
魔法方法之 . 拦截
魔法方法:在类中 __名字__的方法就是魔法方法,特点是某种情况下自动触发
-__init__---->类名()自动触发
-__str__---->print(对象)自动触发
-__getattr__: 对象.属性,如果属性不存在,会触发__getattr__
-__setattr__:对象.属性=值,会触发__setattr__
# 有很多魔法方法---》就想看看有多少
object类中的方法
class Person: def __getattr__(self, item): print(item) # 是name 这个字符串 print(type(item)) # 是name 这个字符串 return 'lqz' def __setattr__(self, key, value): print(key) print(value) # setattr(self,key,value)# 反射内部用的就是setattr 会递归 object.__setattr__(self,key,value) p = Person() # print(p.name) # 会报错,没有这个name时 p.name='彭于晏' print(p.name)