首页 > 其他分享 >drf-序列化字段及参数、序列化和反序列化高级用法、ModelSerializer使用

drf-序列化字段及参数、序列化和反序列化高级用法、ModelSerializer使用

时间:2023-02-02 21:11:28浏览次数:40  
标签:ModelSerializer name models max publish length CharField 序列化 drf

1.序列化类常用字段和字段参数

1.1 常用字段类

1.BooleanField
2 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) 
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)

1.2重要字段类型

CharField
IntegerField
DecimalField
DateTimeField
BooleanField
ListField
DictField

1.3 常用字段参数

1.CharField及其子类(哪些类的父类是CharField需要在源码中查看)的字段参数:
max_length:最大长度
min_length:最小长度
allow_blank:是否允许为空
trim_whitespace	是否截断空白字符

2.InterField参数:
max_value:最大值
min_value:最小值
  
3.所有字段都有的的参数:
required:表明该字段在反序列化时必须输入,默认True
default:反序列化时使用的默认值
allow_null:表名该字段是否允许传入None,默认Flase
validators:该字段使用的验证器
error_messages:包含错误编号与错误信息的字典
label:用于HTML展示API页面时,显示的字段名称
help_text:用于HTML展示API页面时,显示的字段帮助提示信息
    
read_only:表明该字段仅用于序列化输出,默认Flase
write_only:表明该字段仅用于反序列化的输入,默认Flase
    
4.反序列化校验执行流程:
	1.先执行字段自身的校验规则:max_length,max_value
	2.再执行验证器validators
	3.局部钩子校验规则
	4.全局钩子校验规则

2.序列化高级用法之source

models.py:
先创建表,表之间存在数据库层面的联系:
from django.db import models

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)
    
serializer.py:
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 自有字段,直接点名字,通过sourse可以指定models.py中某张表的字段
    name_zzz = serializers.CharField(max_length=8,source='name')
    real_price = serializers.CharField(source='price')
    # 一对多,需要先点外键名到那张表,再点那张表的名字
    publish = serializers.CharField(source='publish.name')
    # 多对多,不能用sourse
    authors = serializers.CharField()
    
views.py:
from app01.serializer import BookSerializer
from .models import Book
from rest_framework.response import Response
from rest_framework.views import APIView

class BookView(APIView):
    def get(self,request):
        book_queryset = Book.objects.all()
        ser = BookSerializer(instance=book_queryset,many=True)
        return Response(ser.data)
"""
通过以上代码演示效果:在serializer.py中无论字段名起什么,只要括号中的source对应models某张表中的某些字段名,在前端就可以显示该名字。它们之间在views.py中通过视图类连接。
"""

3.序列化高级用法之定制字段的两种方式

以上代码存在局限性:首先我们查到出版社,但是我们只能拿到出版社姓名,无法拿到出版社其他信息,其次多对多关系的作者信息我们没法拿到。我们需要通过以下方法来解决。

3.1SerializerMethodField定制

SerializerMethodField是一个定制返回格式的字段类型,该字段类型中不需要填写任何参数,但是方法需要通过写函数来定制指定的返回的格式。返回的数据遵循restful规范:一对多显示字典,多对多显示列表套字典。
serializer.py:
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    name_zzz = serializers.CharField(max_length=8, source='name')
    real_price = serializers.CharField(source='price')

    publish_detail = serializers.SerializerMethodField()
	# 函数名要和字段名保持一致,该字段名也是前端展示的字段名
    def get_publish_detail(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author_list = serializers.SerializerMethodField()

    def get_author_list(self,obj):
        l = []
        for author_obj in obj.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.phone})
        return l
models.py以及views.py代码和上步一样。

3.2在表模型中定制

moodels.py:
from django.db import models

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')
	# 在表模型中定制的函数名要和serializer.py中的字段名保持一致。
    @property
    def publish_detail(self):
        return {'name':self.publish.name,'addr':self.publish.addr}
	# 定制的函数要用@property修饰,可以将方法伪装成一个数据。
    @property
    def author_list(self):
        l = []
        for author_obj in self.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.phone})
        return l
    
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)
    
seriializer.py:
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    name_zzz = serializers.CharField(max_length=8, source='name')
    real_price = serializers.CharField(source='price')

    publish_detail = serializers.DictField()

    author_list = serializers.ListField()

4.多表关联反序列化保存

4.1 反序列化字段校验步骤

1.字段自己的:name = serializers.CharField(max_length=8, error_messages={'max_length': '太长了'})
2.validators=[方法](使用频率较低)
3.局部钩子
4.全局钩子

4.2 新增图书接口

# 前端传入数据的格式:{"name":"新阿q正传","price":"88.66","publish":1,"authors":[2]}
models.py:
from django.db import models

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
    def publish_detail(self):
        return {'name':self.publish.name,'addr':self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author_obj in self.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.phone})
        return l

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)

seriializer.py:
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.Serializer):
    # name和price即用来做序列化,也用来做反序列化,既读又写,所以不用加read_only,write_only
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 用来做序列化,所以要加上read_only=True
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 用来做反序列化,要加上write_only=True,如果不加会在前端看到该字段
    publish = serializers.CharField(write_only=True)
    authors = serializers.ListField(write_only=True)

    # 新增要重写create方法
    def create(self, validated_data):
        # print(validated_data)  {'name': '阿q正传', 'price': '66.66', 'publish': '1', 'authors': [1, 2]}
        # 因为前端上传的是publish的id,所以需要用publish_id=validated_data.get('publish')来新增,如果是对象可以直接用publish新增
        # 取数据的键需要和前端传过来字典的键保持一致
        book_obj = Book.objects.create(name=validated_data.get('name'),price=validated_data.get('price'),publish_id=validated_data.get('publish'))
        # 第三张表要手动写代码新增,一个*数打散列表,两个*用来打散字典
        book_obj.authors.add(*validated_data.get('authors'))
        return book_obj
   
views.py:
class BookView(APIView):
    def get(self,request):
        book_queryset = Book.objects.all()
        ser = BookSerializer(instance=book_queryset,many=True)
        return Response(ser.data)

    def post(self,request):
        # print(request.data)
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'新增成功'})
        else:
            return Response({'code':101,'msg':ser.errors})

前端数据上传尽量使用JSON格式,发现数据新增成功:

4.3 修改图书接口

# 前端传入数据的格式:{"name":"新阿q正传","price":"88.66","publish":1,"authors":[2]}

models.py:
from django.db import models

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
    def publish_detail(self):
        return {'name':self.publish.name,'addr':self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author_obj in self.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.phone})
        return l

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)
  

views.py:
class BookDetailView(APIView):
    def put(self,request,pk):
        book_obj = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(data=request.data,instance=book_obj)
        if ser.is_valid():
            # save需要手动在BookSerializer类中写update方法
            ser.save()
            return Response({'code':100,'msg':'修改成功'})
        else:
            return Response({'code':101,'msg':ser.errors})
 
serializer.py:
from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 用来做序列化
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 用来做反序列化
    publish = serializers.CharField(write_only=True)
    authors = serializers.ListField(write_only=True)

    def create(self, validated_data):
        print(validated_data)
        book_obj = Book.objects.create(name=validated_data.get('name'),price=validated_data.get('price'),publish_id=validated_data.get('publish'))
        book_obj.authors.add(*validated_data.get('authors'))
        return book_obj

    def update(self, instance, validated_data):
        # print(validated_data)  # {'name': '新阿q正传', 'price': '88.66', 'publish': '1', 'authors': [2]}
        # uodate方法中instance就是book对象
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish_id = validated_data.get('publish')
        
        #多对多关系在第三张表上,最好先删除,再写入
        instance.authors.clear()
        instance.authors.add(*validated_data.get('authors'))
        # update方法写完依旧要用修改后的对象点save(),然后返回
        instance.save()
        return instance

5.ModelSerializer使用

ModelSerializer继承自Serializer,完成了很多操作,是之前BookSerializer的简化版:
	-跟表模型强关联
	-大部分请求,不用写create和update了

serializer.py:
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        # 和Book表绑定
        model = Book
        # 中括号内的字段名要和extra_kwargs中的字段名保持一致,并且和models.py中的Book表中的字段名保持一致。
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
        # 定制限制信息
        extra_kwargs = {
            'name': {'max_length': 8},
            'publish_detail': {'read_only': True},
            'author_list': {'read_only': True},
            'publish': {'write_only': True},
            'authors': {'write_only': True}
        }
	# 写钩子函数,要和class Meta:保持相同的缩进
    def validate_name(self, name):
        if name.startswith('sb'):
            raise ValidationError('不能sb')

        else:
            return name
        
models.py:
from django.db import models

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
    def publish_detail(self):
        return {'name':self.publish.name,'addr':self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author_obj in self.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.phone})
        return l


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)
    
views.py:
from app01.serializer import BookSerializer
from .models import Book
from rest_framework.response import Response
from rest_framework.views import APIView


class BookView(APIView):
    def get(self,request):
        book_queryset = Book.objects.all()
        ser = BookSerializer(instance=book_queryset,many=True)
        return Response(ser.data)

    def post(self,request):
        # print(request.data)
        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 BookDetailView(APIView):
    def put(self,request,pk):
        book_obj = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(data=request.data,instance=book_obj)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'修改成功'})
        else:
            return Response({'code':101,'msg':ser.errors})

标签:ModelSerializer,name,models,max,publish,length,CharField,序列化,drf
From: https://www.cnblogs.com/zkz0206/p/17087437.html

相关文章