ModelSerializer使用
ModelSerializer它继承了Serializer,它可以直接跟表模型建立关系
class ModelSerializer(Serializer):
pass
使用方法
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__" # 内部本质:把Book表模型中所有字段,都复制过来的
1 有的字段不想做序列化
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
# 只对book_name,book_price做序列化
fields = ["book_name", "book_price"]
2 publish 默认显示id,我们想显示详情--->重写字段,必须在fields中注册
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ["book_name", "book_price", "publish_dic"]
publish_dic = serializers.DictField()
3 作者显示默认显示id,我们想显示作者详情列表--->重写字段,必须在fields中注册
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ["book_name", "book_price", "publish_dic", "author_list"]
publish_dic = serializers.DictField()
author_list = serializers.ListField()
方法二:------第二种定制字段的方法------看看就行了
publish_dic = serializers.SerializerMethodField()
def get_publish_dic(self, obj):
return {
"publish_name": obj.publish.publish_name,
"publish_addr": obj.publish.publish_addr
}
ModelSerializer的反序列化和数据校验
1 限制name 最长不能超过8
"extra_kwargs"传入
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ["book_name", "book_price", "publish_dic", "authors"]
extra_kwargs = {
"book_name": {"max_length": 8, "min_length": 3}
# 等同于name=serializers.CharField(max_length=8,min_length=3)
}
publish_dic = serializers.DictField()
author_list = serializers.ListField()
2 publish_dict,author_list只做序列化,必须加read_only,-它俩只做反序列化,'publish'、'authors'---->不要写成publish_id,就写成表中的字段
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ["book_name", "book_price", "publish_dic", "author_list", "publish", "authors"]
extra_kwargs = {
"book_name": {"max_length": 8, "min_length": 3},
# 等同于name=serializers.CharField(max_length=8,min_length=3)
"publish": {"write_only": True},
"authors": {"write_only": True},
}
publish_dic = serializers.DictField(read_only=True, )
author_list = serializers.ListField(read_only=True)
# 局部钩子
def validate_name(self, value):
print('我走了--->', value)
return value
# 全局钩子
def validate(self, attrs):
print('我走了--->', attrs)
return attrs
3 之前讲的局部钩子和全局钩子,完全一样
4 可以不重写create和update的。咱们这个案例就不用重写
总结
1、如果使用了:
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
它就会将models.Book这个表上面的字段都映射表中字段,包括字段属性
2、fields = 列表----->要将需要序列化的字段和反序列化的字段放到列表中注册
3、extra_kwargs给某个字段增加属性,包括(read_only,write_only)
4、局部钩子和全局钩子的使用方法还是和以前一样
5、一般情况是不需要写create和updata方法的
6、可以重写字段,但是字段一定不能写到class Mate的内部
模块与包的使用
# 模块与包
-模块:一个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()--->三层---》局部钩子和全局钩子写法是固定---》源码中规定了是要这么写---》如果不这么写,它就执行不了
# 看源码,为什么 局部钩子要 validate_字段名(self,value) 这么写
-入口:ser.is_valid()
def is_valid(self, *, raise_exception=False):
# 如果 self中有_validated_data这个属性--->if就不走了
# 只要_validated_data这个属性有,说明它之前执行过校验了,只要校验过一次,走过一次,以后就不走了
if not hasattr(self, '_validated_data'):
try:
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
# self._errors有值,说明有错误,校验不通过
# raise_exception 默认是false,如果传入的是True,直接抛异常
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
-核心:self._validated_data = self.run_validation(self.initial_data)
-self是谁?序列化类的对象--》BookSerializer---》应该从根上找:BookSerializer
-Serializer 的run_validation
def run_validation(self, data=empty):
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
#1 局部钩子规则
value = self.to_internal_value(data)
try:
#2 放在这里
self.run_validators(value)
# self是 BookSerializer的对象--->validate 全局钩子
#3 全局钩子执行位置--->可以抛异常--->因为捕获了
# value是 校验过后的数据-->而一定要返回
value = self.validate(value)
raise ValidationError(detail=as_serializer_error(exc))
return value
-执行了:self.to_internal_value(data)
def to_internal_value(self, data):
for field in fields: # 序列化类中一个个字段类的对象放到列表中,每次拿出一个字段类对象
# self 是BookSerializer的对象
# 去BookSerializer的对象中反射 validate_字段名
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
if validate_method is not None:
# 如果有值,就会执行局部钩子,传入待校验的数据,局部钩子必须返回数据
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
return ret
总结
只要执行序列化类对象的.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_字段名
![](D:\Course notes\python\drf\Day05 drf-ModelSerializer使用\代码\drf-day05.assets\image-20230901115047088.png)
断言
# assert 关键字,断定这个条件是符合的,才能往下走,如果不符合,就抛异常
写法:
assert 条件,不符合抛出的异常
Eg:
age = 10
assert age=8 ,"age的值必须为10"
用代码来翻译:
if not age=="10":
raise Exception("age的值必须为10")
def请求
请求源码分析
# from rest_framework.request import Request
# 1 以后视图类的方法中的request都是这个类的对象
# 2 以后使用request.data 取请求体中的数据
# 3 以后使用request.query_params 取请参数中的数据
# 4 以后其他属性,用起来跟之前一样--->重要
为什么我还可以直接使用request.method方法?
当我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) # item拿到的是对象.的属性名
return "hhh" # 返回什么这个p.name=返回值,什么都不写返回None
def __setattr__(self, key, value):
print("++++++", key, value) # ++++++ name 彭于晏
object.__setattr__(self, key, value)
p = Person()
# print(p.name)
p.name = "彭于晏"
print(p.name) # 彭于晏