首页 > 其他分享 >drf day04 序列化高级用法、ModelSerializer、字段参数source

drf day04 序列化高级用法、ModelSerializer、字段参数source

时间:2023-02-02 21:35:41浏览次数:40  
标签:None ModelSerializer name models max source 序列化 data

一个小作业

自己写代码,让原生的request能实现request.data传值

思路:写装饰器,装饰request.data,做到2+1都是request.data


def MyRequest(func):
    def inner(request, *args, **kwargs):
        try:
            print(request.body)
            request.data = json.loads(request.body)

        except Exception as e:
            request.data = request.POST

        res = func(request, *args, **kwargs)
        return res

    return inner


@MyRequest  # 等于MyRequest(TestView)(request)   就是inner(request)
def TestView(request):
    print(request.POST)
    print(request.data)
    return HttpResponse('ok')

一、ModelSerializer的使用

前话:序列化组件在写字段时,可以做约束,但是不是约束序列化,而是约束反序列化,

类似form组件的字段约束

ModelSerializer可以不用写字段,不用重写create、update方法

class Authorserializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'  #这是把所有字段全都序列化了
        #可以选择只序列化某几个字段
        fields = [要序列化、反序列化的字段]
        
上面Meta这一堆,就相当于Serializer的正常的写字段,映射出来的而已

此外,还可以在这里面(是外面大类不是Meta里面!)重写字段,后执行的是真正生效的(这个简单一些好理解)

重点————也可以不重写字段,但是可以往里面加属性
	model = Author
        fields = '__all__'  #这是把所有字段全都序列化了
        #可以选择只序列化某几个字段
        fields = [要序列化、反序列化的字段]
        extra_kwargs = {'字段':{要加的属性字典}}  

二、序列化组件中常用字段和字段参数

1.常用字段类(熟小部分,了解大部分)

BooleanField	           BooleanField()
NullBooleanField	       NullBooleanField()
CharField	               CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField	             EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField	             RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField	               SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField	               URLField(max_length=200, min_length=None, allow_blank=False)
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"
IPAddressField	         IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
IntegerField	           IntegerField(max_value=None, min_value=None)
FloatField	             FloatField(max_value=None, min_value=None)
DecimalField	           DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None,          min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField	           DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField	               DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField	               TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField	           DurationField()
ChoiceField	             ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField	     MultipleChoiceField(choices)
FileField	               FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
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=)

————————————下面两个重要
#ListField:{name:'kevin',age:19,hobby:['唱','跳']}
#DictField:{name:'kevin',age:19,city:{'name':'上海','name':'北京'}}

​ 重点记住

CharField
BooleanField
IntergerField
DecimalField

2.常用字段参数

选项参数:

# CharField及其子类的(EmailField) ---》反序列化的校验,字段自己的规则
    max_length	最大长度
    min_lenght	最小长度
    allow_blank	是否允许为空
    trim_whitespace	是否截断空白字符

# IntegerField
    max_value	最小值
    min_value	最大值

    
# 所有字段类都有的
required	表明该字段在反序列化时必须输入,默认True
default	    反序列化时使用的默认值
allow_null	表明该字段是否允许传入None,默认False
validators	该字段使用的验证器
error_messages	包含错误编号与错误信息的字典
----不常用-----
label	用于HTML展示API页面时,显示的字段名称
help_text	用于HTML展示API页面时,显示的字段帮助提示信息


# 重点:
read_only	表明该字段仅用于序列化输出,默认False,常用
write_only	表明该字段仅用于反序列化输入,默认False,常用


## 反序列化校验执行流程,其实是有四步的,第二个一般可以忽略
	-1 先执行字段自己的校验规则----》最大长度,最小长度,是否为空,是否必填,最小数字。。。。
    -2 validators=[方法,] ----》单独给这个字段加校验规则
    	好处是可以给很多个字段都用这个方法
    	name=serializers.CharField(validators=[方法,])
    -3 局部钩子校验规则
    -4 全局钩子校验规则

三、字段参数source的使用

​ 几句话,在序列化字段时,后端数据库中表的字段可以变为另外的名字传给前端拿,新字段属性中 + source='老字段名'

​ 另外,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')

    
    def new_name(self):
        return f'此书叫做{self.name}'
    

#序列化类
class BookSerializers(serializers.Serializer):
    name_book = serializers.CharField(source='new_name')
    price = serializers.CharField()

​ 还可以做跨表查询(要用外键对象点字段),一对多直接点,多对多搞不了

​ 注意:因为在序列化类过程中,视图函数中序列化了对象——绑定着一张表,如果基于这个表找东西可以省略表名,比如book.publish.name 可以省略book,这就是source='啥啥啥'是在序列化模型表中找属性的根本原因

接下来要学习重要的东西,准备全新的表,注意,因为我们已经创建过Book表,复制下面的表代码进去做数据库迁移会出问题,建议直接把项目停了,然后去删除sqlite3,然后迁移就没问题了

如果还是各种报错,重新开一个项目吧2333

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateTimeField()

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name
    
    def new_name(self):
        return f'这本书名叫{self.name}'

class Author(models.Model):
    name = models.CharField(max_length=8)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    name = models.CharField(max_length=16)
    addr = models.CharField(max_length=8)
    email = models.EmailField(null=True)
    
    
    
 由于表关联太多,录入数据不好录入,建议去admin后台录入,具体流程就不说了,创建一个admin超级用户就可以去admin后台   
    

四、序列化高级用法之定制字段的两种方式(重要)

​ 首先,我们想拿一下一对多、多对多的字段序列化给前端看看,记得哦,因为是多对多外键,source='authors.all'才是能拿到所有作者对象的QS

1.关联字段的显示形式SerializerMethodField


一对多的显示字典
	序列化类中新增条这个
	publish=serializers.SerializerMethodField()
    然后!一定要跟上一个方法一定要是get_字段名,return啥,前端就显示啥,obj就是后端查到的对象
    def get_publish(self,obj):
       return {'name':obj.publish.name,'city':obj.publish.city}


多对多的显示列表套字典
    authors_detail = serializers.SerializerMethodField()

    def get_authors_detail(self, obj):
        author_list = []
        for i in obj.authors.all():
            author_list.append({'name': i.name, 'age': i.age, 'detail':
                {'addr': i.author_detail.addr, 'phone': i.author_detail.telephone}})

        return author_list

2.在表模型中写方法——很有趣,推荐

​ 因为序列化类就是在模型表中点属性,所以我们就在模型表中封方法,当这个方法被调用就返回前面写过的那种

一对多的:
	@proprey
    def publish_detail(self):
        return {'name':self.publish.name,'city':self.publish.city}
    
  然后序列化类中:
	publish_detail=serializers.DictField()
    

多对多的:
	@proprey
	 def author_list(self):
        list = []
        for i in self.authors.all():
            list.append({'name':i.author.name,'phone':i.author.phone})
       return list


# 也可以用列表生成式直接传出去
     #   return [{'name': i.name, 'age': i.age, 'detail':
     #       {'addr': i.author_detail.addr, 'phone': i.author_detail.telephone}} for i in self.authors.all()]
	然后序列化类中:
    author_list=serializers.ListField()

五、多表关联的反序列化

用到了read_only=True write_only=True属性
让我们的序列化类,能根据读写请求方式的不同选择不同的字段

1.反序列化之新增一个表数据
视图层的其实基本一致
    def post(self, request):
        ser = BookSerializers(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response ({'code': 1000, 'msg': '新增成功'})
        else:
            return Response ({'code': 1001, 'msg':ser.errors })

 序列化类层的      
    然后重写create方法
    def create(self, validated_data):
        print(validated_data) #这里打一下看看
        #注意,接下来干的是图方便,所以必须把
        #publish= serializers.CharField(write_only=True)改为
        #publish_id = serializers.CharField(write_only=True)
        #因为要让前端传过来的publish_id和book表的字段对应上,不然就报错
        authors = validated_data.pop('authors')
        #这里是先移除掉authros,剩下的kv键值对一次丢进去创建
        book = Book.objects.create(**validated_data)

        book.authors.add(*authors) #这个方法很久没用了,是用于有关联关系的第三张表的数据添加,用于多对多
        return book
    
    #前端传数据时一定要注意K要对的上啊!!!!
    
    
2.反序列化之新增一个表数据
视图层的其实基本一致
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        #这里可以加点判断,我就不写了
        ser = BookSerializers(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 1000, 'msg': '新增成功'})
        else:
            return Response({'code': 1001, 'msg': ser.errors})
        
        
 序列化类层:
    def update(self, instance, validated_data):
		#先弹出不能for循环一次写入的K
        authors = validated_data.pop('authors')
        print(validated_data)
        #这里用了反射,就非常简单了
        for i in validated_data:
            setattr(instance, i, validated_data[i])

        # instance.name = validated_data.get('name')
        # instance.price = validated_data.get('price')
        # instance.publish_id = validated_data.get('publish_id')

        instance.authors.clear() # 先清空书和作者的关联关系再添加
        instance.authors.add(*authors)
        instance.save()
        return instance

六、今日犯错

  • 1.一对多ORM跨表查询,多的那张表根据外键字段自动产生外键字段_id的一个字段

    ​ 跨表查询是那自己写模型表时写的外键字段,而不是外键字段_id 点半天报错!!!

  • 2.写序列化跨表查询一对多字段时,字段和get_字段函数名字不统一,一直在报错

  • ORM 之多对多关系表 的 add()那四个方法忘记怎么用了

  • 写新增接口时,因为图方便,直接pop一个数据后全**validated_data创建新的表数据,然后因为前端自己传的publish作为K想当 外键publish_id 来创建,当然创建不了啊!!!book表中都没这个publish 字段,因为被外键搞成了publish_id了!

标签:None,ModelSerializer,name,models,max,source,序列化,data
From: https://www.cnblogs.com/wznn125ml/p/17087483.html

相关文章