首页 > 其他分享 >DRF 04 序列化反序列化的功能实现

DRF 04 序列化反序列化的功能实现

时间:2023-02-02 21:00:09浏览次数:43  
标签:serializers name 04 max publish length 序列化 DRF

作业:

# 原生的django中request中是没有data的,但是通过下面的这个装饰器就能实现通过点data也能获取到数据
def wrapper(func):
    # 通过装饰器做装饰视图的,以后都会有request
    def inner(request,*args,**kwargs):
        '''
        想要通过这个装饰器来使test功能也能从data里面拿到数据
        1.创造一个新的request
        2.如果是urlencoded,form-data 点request.POST,就有值
        3.如果request.POST 没有值,就是竞赛你格式
        '''
        try:
            request.data=json.loads(request.body) # 这里表示的就是叫你格式的编码
        except Exception as e:
            request.data=request.POST
        res=func(request,*args,**kwargs)
        return res
    return inner
@wrapper
def test(request):
    print(request.POST)
    print(request.data)
    return HttpResponse('实验成功')

总结:前端提交数据的编码格式

  • urlencoded :
    • name=lqz&age=19&price=999 放在了请求体中
  • form-data:
    • 分数据部分和文件部分
    • mdata: 分数据部分和文件部分
      文件部分是一堆二进制码 '------585520151165741599946333\r\n
    • form-datat name="name"\r\n\r\nlqz\r\
  • json格式:

序列化常用字段和字段参数

序列化类 
	字段类 CharFiled,
    字段属性 max_length=
序列化类有字段类,字段类能传属性,序列化类也能写属性
	【models.CharField(max_length=32)】

1.常用字段类

1. BooleanField	      BooleanField()

2. NullBooleanField	  NullBooleanField()

3. CharField	CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)

4. EmailField	EmailField(max_length=None, min_length=None, allow_blank=False)

5. RegexField	RegexField(regex, max_length=None, min_length=None, allow_blank=False)

6. SlugField	SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+

7. URLField	URLField(max_length=200, min_length=None, allow_blank=False)

8. UUIDField	UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"

9. IPAddressField	IPAddressField(protocol=’both’, unpack_ipv4=False, **options)

10. IntegerField	IntegerField(max_value=None, min_value=None)

11. FloatField	FloatField(max_value=None, min_value=None)

12. DecimalField	DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置

13. DateTimeField	DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)

14. DateField	DateField(format=api_settings.DATE_FORMAT, input_formats=None)

15. TimeField	TimeField(format=api_settings.TIME_FORMAT, input_formats=None)

16. DurationField	DurationField()

17. ChoiceField	ChoiceField(choices) choices与Django的用法相同

18. MultipleChoiceField	MultipleChoiceField(choices)

19. FileField	FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

20. ImageField	ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

ListField	ListField(child=, min_length=None, max_length=None)
DictField	DictField(child=)


#最常用的:CharField  IntegerField  DecimalField  DateTimeField BooleanField
ListField
DictField

2.常用字段参数

# CharFiled 极其子类的(EmailFiled) 反序列化的校验,字段都是有自己的规则的
	max_length  最大长度
    min_length  最小长度
    allow_blank  是否允许为空
    trim_withespace  是否截断空白字符
    
# IntegerFiled
	max_value 最大值
    min_value 最小值
    
# 所有字段类中都有的属性
	required	表明该字段在反序列化时必须输入,默认是True
    default		反序列化时设置默认值
    zllow_null	表明该字段是否允许传入None,默认是False
   - 下面的属性使用的不多
	error_messages	包含错误编码与错误信息的字典
    label	用于HTML展示API页面时,显示字段名称
    help_text	用于HTML展示API页面时,显示的字段帮助提示信息
    
# 重要
	read_only	表明该字段仅用于序列化输出,默认是False
    write_only 表明该字段仅用于反序列化输入,默认值False
    
# 反序列化校验流程
	1.先执行字段自己的校验规则,(最大长度,最小长度,是否为空,。。。。)
    2.validators=[def(方法)],单独给某个字段加校验规则
    name=serializers.CharField(validators=[方法,])
    3.局部钩子校验
    4.全局钩子校验

3.序列化使用---source(了解)

代码如下:

# 创建关联表
class Book(models.Model):
    """'''图书表'''"""
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    # 图书和出版社是一对多关系
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    # 图书和作者是多对多的关系
    authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    """'''出版社表'''"""
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)


class Author(models.Model):
    """'''作者表'''"""
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=11)

4.序列化制定字段名字

class BookSerializer(serializers.Serializer):
    # 定制专门的字段名 字段参数
    name1=serializers.CharField(max_length=8,source='name')
    price1=serializers.CharField(source='price')
    """
    source :如果是自由字段就直接写
            关联字段就直接点
            多对多关联字段不能使用source
    """
    publish=serializers.CharField(source='publish.name')
    # 多对多关联字段不能使用source
    authors=serializers.CharField(source='authors.all')
 
一对多关联字段除了上面的这种还能在模型层中Publish中直接:
	    # 直接在这里指定publish的名字
    def __str__(self):
        return self.name
注意事项:
	使用source定制字段名不能和定制的的字段名重复,否则就会报错

image

ps:字段名的定制是为了提高数据库的安全性所设计的(字段名)

一对多,多对多序列化定制字段名

SerializerMethodField定制
# 显示形式
	一对多显示的是字典
	多对多显示是列表套字典
### 高级序列化
class BookSerializer(serializers.Serializer):
    # 定制专门的字段名 字段参数
    name1=serializers.CharField(max_length=8,source='name')
    price1=serializers.CharField(source='price')
    # 定制返回格式方式一
    publish=serializers.SerializerMethodField()
    # 使用这个属性必须要配合下面的这个方法
    """在这里return的是什么数据展示的就是什么数据,而且get后面跟的必须和字段名一样"""
    def get_publish(self,obj):
        return {'name':obj.publish.name,'addr':obj.publish.addr}
    author_list=serializers.SerializerMethodField()
    def get_author_list(self,obj):
        l1=[]
        for author in obj.authors.all():
            l1.append({'name':author.name,'phone':author.phone})
        return l1
方法二:

在模型表中定制

class Book(models.Model):
    """'''图书表'''"""
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    # 图书和出版社是一对多关系
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    # 图书和作者是多对多的关系
    authors = models.ManyToManyField(to='Author')

    # 把方法包装成数据属性 @property加不加都可以
    @property
    def publish_detail(self):
        return{'name':self.publish.name,'addr':self.publish.addr}

    @property
    def author_list(self):
        l1 = []
    #         for author in obj.authors.all():
    #             l1.append({'name':author.name,'phone':author.phone})
    #         return l1
        return [{"name":author.name, "phone":author.phone}  for author in self.authors.all() ]

# 序列化类
### 模型表中定制字段
class BookSerializer(serializers.Serializer):
    # 定制专门的字段名 字段参数
    name1=serializers.CharField(max_length=8,source='name')
    price1=serializers.CharField(source='price')
    # 定制返回格式方式一
    publish_detail=serializers.DictField()
    author_list=serializers.ListField()

多表关联反序列化保存

新增图书接口

# 新增一个图书接口
	-{name:水浒传,price:88,publish:(下拉选择出版社),author:[1,2]}

代码如下

 # 视图层
    class BookView(APIView):
    def post(self,request):
        ser=BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'添加成功'})
        else:
            return Response({'code':101,'msg':ser.errors})

# 序列化类
	class BookSerializer(serializers.Serializer):
    # 这个字段既能序列化也能返序列化,既能读也能写
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()
    # 只能做序列化功能 只能读 read_only
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 只能用来做反序列化功能, 只能写 write_only
    publish = serializers.CharField(write_only=True)
    authors = serializers.ListField(write_only=True)

    # 添加功能
    """新增数据必须要重写create方法"""

    def create(self, validated_data):
        """
        validated_data: 是新增的数据
        """
        # 新增一本图书
        book = Book.objects.create(name=validated_data.get('name'),
                                   price=validated_data.get('price'),
                                   publish_id=validated_data.get('publish')
                                   )
        # 作者也需要关联字段  多读点关联
        book.authors.add(*validated_data.get('authors'))
        return book

修改图书接口

代码:

# 序列化类
class BookSerializer(serializers.Serializer):
    # 这个字段既能序列化也能返序列化,既能读也能写
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()
    # 只能做序列化功能 只能读 read_only
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 只能用来做反序列化功能, 只能写 write_only
    publish = serializers.CharField(write_only=True)
    authors = serializers.ListField(write_only=True)

    # 重写修改方法
    def update(self, instance, validate_data):
        instance.name = validate_data.get('name')
        instance.price = validate_data.get('price')
        instance.publish_id = validate_data.get('publish')
        # 因为原来的数据流式一个列表,而两个列表相加数据就会重复
        authors = validate_data.get('authors')
        # 先将原先的authors里面的数据清空
        instance.authors.clear()
        # 再将数据添加进去
        instance.authors.add(*authors)
        instance.save()
        return instance

# 视图类
class BookViews(APIView):
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功'})
        else:
            return Response({'code': 101, 'msg': ser.errors})
        
#路由添加
	urlpatterns = [ path('books/<int:pk>/',views.BookViews.as_view())
]
小结:
  • 关于read_only 和write_only 可以分别写在序列化和反序列化两个类中

  • 在序列化和反序列化的时候一定要用read_only和write_only来控制

  • 中文显示提示

    • ANGUAGE_CODE = 'zh-hans'
      TIME_ZONE = 'Asia/Shanghai
      USE_TZ = False
      

反序列化字段校验其他

校验的数据一共有四层:
	-1.字段类自己的校验规则
    	name = serializers.CharField(max_length=8,error_messages={})
	-2.validators=[def(方法)],单独给某个字段加校验规则
    name=serializers.CharField(validators=[方法,])
    -3.局部钩子校验
    -4.全局钩子校验

ModelSerializer使用

ModelSerializer 是继承了serializer,添加很多的功能,完成很多的操作
	- 跟表模型是强关联,只能是使用的是哪个表,就只能哪个表用这里面的功能
	- 不需要写create和update

使用方法

class BookSerializer(serializers.ModelSerializer):
    #  和表建立关系
    class Meta:
        model = Book  # 序列化类和表建立了关系
        # fields = '__all__'  # 序列化所有的数据
        """
        在Meta中写了__all__就相当于是复制了表模型类中的所有字段,放在这里
        做了一个映射
        """
        # 下面重写的数据一定要到这里注册,否则可能会报错
        fields=['name','price','publish','author_list','publish_detail','authors']

        # 单独给name定制反序列化的校验规则 给字段添加属性 方式一
        extra_kwargs = {'name': {'max_length': 8},
                        'publish':{'write_only':True},
                        'authors':{'write_only':True},
                        'publish_detail':{'read_only':True},
                        'author_list':{'read_only':True}
                        }

    # 单独给name定制校验规则 重写name字段  方法二  【一定要写在Meta的外面】优先使用这种方法
    # name = serializers.CharField(max_length=7)
    # # 把这个功能序列化写成和之前一模一样 序列化一定要加上read_only 而且在这里写了之后一定要到上面去注册
    # publish_detail = serializers.SerializerMethodField(read_only=True)
    # def get_publish_detail(self, obj):
    #     return {'name': obj.publish.name, 'addr': obj.publish.addr}
    # author_list = serializers.SerializerMethodField(read_only=True)
    #
    # def get_author_list(self, obj):
    #     l1 = []
    #     for author in obj.authors.all():
    #         l1.append({'name': author.name, 'phone': author.phone})
    #     return l1

    # 局部钩子和之前的是一样的
    def validate_name(self, name):
        if name.startswith('xxx'):
            raise ValidationError('不能以xxx作为开头')
        else:
            return name
总结:
  • 通过Meta和模型类强关联
  • fields 是序列化的的所有字段
  • extra_kwargs= 用来定制字段类的属性
  • 如果是在fileds中写了__all__就是将模型表中的字段名全部复制了过来,做了个映射
  • 还可以通过重写来定制字段类的属性
  • 最后总结一句话,ModelSerializer继承了Serializer,所有的功能还是和之前一模一样,还能写一些自己的功能,更加的简洁,有了私有性。

标签:serializers,name,04,max,publish,length,序列化,DRF
From: https://www.cnblogs.com/qiguanfusu/p/17087405.html

相关文章