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) # 彭于晏

posted on 2023-09-02 16:59  Way*yy  阅读(8)  评论(0编辑  收藏  举报