ModelSerializer 模型序列化

ModelSerializers 默认帮我们实现了创建和更新方法,简化了我们的操作,当然如果你想自己写,可以重写它。其余使用方法跟普通的序列化一样。

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('id', 'title', 'vnum', 'content')       三者取一
       #exclude = () 表示不返回字段        三者取一
       #fields = '__all__': 表示所有字段       三者取一

       #read_only_fields = () #设置只读字段 不接受用户修改


内部类

# 概念:将类定义在一个类的内部,被定义的类就是内部类
# 特点:内部类及内部类的所以名称空间,可以直接被外部类访问的
# 应用:通过内部类的名称空间,给外部类额外拓展一些特殊的属性(配置),典型的Meta内部类 - 配置类

class Book(model.Model):
    class Meta:
        db_model = "owen_book"  # 配置自定义表名
        
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = "Book"  # 配置序列化类绑定的Model表

DRF 响应类 Response

"""
def __init__(self, data=None, status=None, template_name=None, headers=None, 								exception=False, content_type=None):
    pass
    
data:响应的数据 - 空、字符串、数字、列表、字段、布尔
status:网络状态码
template_name:drf说自己也可以支持前后台不分离返回页面,但是不能和data共存(不会涉及)
headers:响应头(不用刻意去管)
exception:是否是异常响应(如果是异常响应,可以赋值True,没什么用)
content_type:响应的结果类型(如果是响应data,默认就是application/json,所有不用管)
"""


# 常见使用
Response(
    data={
        'status': 0,
        'msg': 'ok',
        'result': '正常数据'
    }
)

Response(
    data={
        'status': 1,
        'msg': '客户端错误提示',
    },
	status=status.HTTP_400_BAD_REQUEST,
	exception=True
)

序列化基类控制的初始化参数

"""
def __init__(self, instance=None, data=empty, **kwargs):
    pass

instance:是要被赋值对象的(序列化) - 对象类型数据赋值给instance
data:是要被赋值数据的(反序列化) - 请求来的数据赋值给data
kwargs:内部有三个属性:many、partial、context
    many:操作的对象或数据,是单个的还是多个的
    partial:在修改需求时使用,可以将所有校验字段required校验规则设置为False
    context:用于视图类和序列化类直接传参使用
"""

# 常见使用
# 单查接口
UserModelSerializer(instance=user_obj)

# 群查接口
UserModelSerializer(instance=user_query, many=True)

# 增接口
UserModelSerializer(data=request.data)

# 整体改接口
UserModelSerializer(instance=user_obj, data=request.data)

# 局部改接口
UserModelSerializer(instance=user_obj, data=request.data, partial=True)

# 删接口,用不到序列化类

反序列化

views.py 反序列化生成模型对象

class UserAPIView(APIView):
    def post(self, request, *args, **kwargs):
        # 单增
        # 1)将前台请求的数据交给序列化类处理
        # 2)序列化类执行校验方法,对前台提交的所有数据进行数据校验:校验失败就是异常返回,成功才能继续
        # 3)序列化组件完成数据入库操作,得到入库对象
        # 4)响应结果给前台
        serializer = serializers.UserModelSerializer(data=request.data)
        if serializer.is_valid():
            # 校验成功 => 入库 => 正常响应
            obj = serializer.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'result': '新增的那个对象'
            }, status=status.HTTP_201_CREATED)
        else:
            # 校验失败 => 异常响应
            return Response({
                'status': 1,
                'msg': serializer.errors,
            }, status=status.HTTP_400_BAD_REQUEST)

serializers.py

"""
标注:序列化 => 后台到前台(读)  |  反序列化 => 前台到后台(写)
1)不管是序列化还是反序列化字段,都必须在fields中进行声明,没有声明的不会参与任何过程(数据都会被丢弃)

2)用 read_only 表示只读,用 write_only 表示只写,不标注两者,代表可读可写

3)
i)自定义只读字段,在model类中用@property声明,默认就是read_only
@property
def gender(self):
	return self.get_sex_display()
	
ii)自定义只写字段,在serializer类中声明,必须手动明确write_only
re_password = serializers.CharField(write_only=True)

特殊)在serializer类中声明,没有明确write_only,是对model原有字段的覆盖,且可读可写
password = serializers.CharField()

4)用 extra_kwargs 来为 写字段 制定基础校验规则(了解)

5)每一个 写字段 都可以用局部钩子 validate_字段(self, value) 方法来自定义校验规则,成功返回value,失败抛出 exceptions.ValidationError('异常信息') 异常

6)需要联合校验的 写字段们,用 validate(self, attrs) 方法来自定义校验规则,,成功返回attrs,失败抛出 exceptions.ValidationError({'异常字段': '异常信息'}) 异常

7)extra_kwargs中一些重要的限制条件
	i)'required':代表是否必须参与写操作,有默认值或可以为空的字段,该值为False;反之该值为True;也可以手动修改值
"""

"""
开发流程:
1)在model类中自定义 读字段,在serializer类中自定义 写字段
2)将model自带字段和所以自定义字段书写在fields中,用write_only和read_only区别model自带字段
3)可以写基础校验规则,也可以省略
4)制定局部及全局钩子
"""
from rest_framework import serializers
from rest_framework import exceptions

from . import models
class UserModelSerializer(serializers.ModelSerializer):
    # 自定义反序列化字段(所有校验规则自己定义,也可以覆盖model已有的字段)
    # 覆盖model有的字段,不明确write_only会参与序列化过程
    password = serializers.CharField(min_length=4, max_length=8, write_only=True)
    # 自定义字段,不明确write_only序列化会报错,序列化会从model中强行反射自定义字段,但是model没有对于字段
    re_password = serializers.CharField(min_length=4, max_length=8, write_only=True)


    class Meta:
        # 该序列化类是辅助于那个Model类的
        model = models.User
        # 设置参与序列化与反序列化字段
        # 插拔式:可以选择性返回给前台字段(插头都是在Model类中制造)
        # fields = ['name', 'age', 'height', 'sex', 'icon]

        # 第一波分析:
        # 1)name和age,在fields中标明了,且没有默认值,也不能为空,入库时必须提供,所有校验时必须提供
        # 2)height,在fields中标明了,但是有默认值,所有前台不提供,也能在入库时采用默认值(可以为空的字段同理)
        # 3)password,没有在fields中标明了,所以校验规则无法检测password情况,但是即使数据校验提供了,
        #       也不能完成入库,原因是password是入库的必备条件
        # 4)gender和img是自定义插拔@property字段,默认就不会进行校验(不参与校验)
        # fields = ['name', 'age', 'height', 'gender', 'img']

        # 第二波分析:
        # 1)如何区分 序列化反序列化字段 | 只序列化字段(后台到前台) | 只反序列化字段(前台到后台)
        #       不做write_only和read_only任何限制 => 序列化反序列化字段
        #       只做read_only限制 => 只序列化字段(后台到前台)
        #       只做write_only限制 => 只反序列化字段(前台到后台)

        # 2)对前台到后台的数据,制定基础的校验规则(了解)
        #       CharField(max_length, min_length, errors_kwargs)
        #       DecimalField(min_value, max_value, max_digits, decimal_places,error_messages)

        # 3)如果一个字段有默认值或是可以为空,比如height,如何做限制
        #       虽然有默认值或是可以为空,能不能强制限制必须提供,可以通过required是True来限制
        #       前台提交了该字段,我就校验,没提交我就不校验:1)required是False 2)有校验规则
        fields = ['name', 'age', 'password', 'height', 'gender', 'img', 're_password']

        # 第三波分析
        # 1)制定的简易校验规则(没有制定)后,可以再通过字段的 局部钩子 对该字段进行复杂校验
        # 2)每个字段进行逐一复杂校验后,还可以进行集体的 全局钩子 校验
        #       涉及对自定义反序列化字段的校验:re_password(要参与校验,但是不会入库)

        # 校验规则
        extra_kwargs = {
            'name': {
                # 'write_only': True,
                # 'read_only': True
            },
            'password': {
                'write_only': True,
                'min_length': 3,
                'max_length': 8,
                'error_messages': {  # 可以被国际化配置替代
                    'min_length': '太短',
                    'max_length': '太长'
                }
            },
            'height': {
                # 'required': True,
                'min_value': 0,
            }
        }

    # 注:局部全局钩子,是和Meta同缩减,属于序列化类的
    # 局部钩子:validate_要校验的字段(self, 要校验的字段值)
    # 全局钩子:validate(self, 所以字段值的字典)
    # 校验规则:成功返回传来的数据 | 失败抛出异常

    def validate_name(self, value):
        if 'g' in value.lower():
            raise exceptions.ValidationError("这个g不行")
        else:
            return value

    def validate(self, attrs):
        print(attrs)
        password = attrs.get('password')  # 只是拿出来校验
        re_password = attrs.pop('re_password')  # 必须取出校验,因为不能入库

        if password != re_password:
            raise exceptions.ValidationError({'re_password': '两次密码不一致'})
        else:
            return attrs


models.py

from django.db import models
from django.conf import settings
class User(models.Model):
    SEX_CHOICES = ((0, '男'), (1, '女'))
    name = models.CharField(max_length=64, verbose_name='姓名')
    password = models.CharField(max_length=64)
    age = models.IntegerField()
    height = models.DecimalField(max_digits=5, decimal_places=2, default=0)
    sex = models.IntegerField(choices=SEX_CHOICES, default=0)
    # sex = models.CharField(choices=[('0', '男'), ('1', '女')])
    icon = models.ImageField(upload_to='icon', default='icon/default.png')

    # 自定义序列化给前台的字段
    # 优点:1)可以格式化数据库原有字段的数据 2)可以对外隐藏原有数据库字段名 3)可以直接连表操作
    @property  # 制造插头
    def gender(self):
        return self.get_sex_display()

    @property
    def img(self):
        return settings.BASE_URL + settings.MEDIA_URL + self.icon.name

    def __str__(self):
        return self.name

 posted on 2020-02-20 18:36  Rannie`  阅读(214)  评论(0编辑  收藏  举报
去除动画
找回动画