序列化器-Serializer 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型 反序列化,完成数据校验功能 1.定义序列化器 Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
接下来,为了方便演示序列化器的使用,我们先创建一个新的子应用sers
1 python manage.py startapp sers
在settings.py
注册sers
1 2 3 4 INSTALLED_APPS = [ .... 'sers', ]
我们创建几个图书相关模型
1 2 3 4 5 6 7 from django.db import modelsclass Book (models.Model): title = models.CharField(max_length=32 ,verbose_name="书籍名称" ) price = models.IntegerField(verbose_name="价格" ) pub_date = models.DateField(verbose_name="出版日期" )
我们想为Book模型类提供一个序列化器,可以定义如下:
1 2 3 4 5 6 from rest_framework import serializersclass BookSerializer (serializers.Serializer): title = serializers.CharField() price = serializers.IntegerField() pub_date = serializers.DateField()
**注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。**serializer是独立于数据库之外的存在。
常用字段类型 常用字段类型 :
字段 字段构造方式 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(max_length=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=)
选项参数:
参数名称 作用 max_length 最大长度 min_lenght 最小长度 allow_blank 是否允许为空 trim_whitespace 是否截断空白字符 max_value 最小值 min_value 最大值
通用参数:
参数名称 说明 read_only 表明该字段仅用于序列化输出,默认False write_only 表明该字段仅用于反序列化输入,默认False required 表明该字段在反序列化时必须输入,默认True default 反序列化时使用的默认值 allow_null 表明该字段是否允许传入None,默认False validators 该字段使用的验证器 error_messages 包含错误编号与错误信息的字典 label 用于HTML展示API页面时,显示的字段名称 help_text 用于HTML展示API页面时,显示的字段帮助提示信息
2.创建Serializer对象 定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:
1 Serializer(instance=None , data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance 参数
2)用于反序列化时,将要被反序列化的数据传入data 参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context 参数额外添加数据,如
1 serializer = AccountSerializer(account, context={'request' : request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。 序列化器的字段声明类似于我们前面使用过的表单系统。 开发restful api时,序列化器会帮我们把模型数据转换成字典. drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典. 3.序列化器的使用 序列化器的使用分两个阶段:
在客户端请求时,使用序列化器可以完成对数据的反序列化。 在服务器响应时,使用序列化器可以完成对数据的序列化。 序列化 基本序列化使用
1) 先查询出一个图书对象
1 2 from sers.models import Bookbook = Book.objects.get(pk=1 )
2) 构造序列化器对象
1 2 from .serializers import BookSerializerbookSer = BookSerializer(instance=book)
3)获取序列化数据
通过data属性可以获取序列化后的数据
4)如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True 参数补充说明
1 2 3 4 5 6 7 class BookView (APIView ): def get (self, request ): books = Book.objects.all () bs = BookSerializer(instance=books, many=True ) return Response(bs.data)
反序列化 数据验证 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用**is_valid()**方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors 属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY 来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data 属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
如我们前面定义过的BookSerializer
1 2 3 4 5 6 from rest_framework import serializersclass BookSerializer (serializers.Serializer): title = serializers.CharField() price = serializers.IntegerField() pub_date = serializers.DateField()
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
1 2 3 4 5 6 7 8 from sers.sers import BookSerializerbs = BookSerializer(data={"title" :"小王子" ,"price" :100 }) bs.is_valid() False bs.validated_data {} bs.errors {'pub_date' : [ErrorDetail(string='This field is required.' , code='required' )]}
可以设置required=False让校验字段可以为空!
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True 参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
1 2 serializer.is_valid(raise_exception=True )
如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:
validate_字段名 对<field_name>
字段进行验证,如
1 2 3 4 5 6 7 8 9 class BookSerializer (serializers.Serializer): title = serializers.CharField(max_length=32 ) price = serializers.IntegerField(required=True ) pub_date = serializers.DateField(required=True ) def validate_title (self, value ): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的" ) return value
测试
1 2 3 4 5 6 from sers.sers import BookSerializerbs = BookSerializer(data={"title" :"小王子" ,"price" :100 }) bs.is_valid() False bs.errors {'title' : [ErrorDetail(string='图书不是关于Django的' , code='invalid' )], 'pub_date' : [ErrorDetail(string='This field is required.' , code='required' )]}
还有一种写法:
1 2 3 4 5 6 7 8 def title_django (self, value ): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的" ) return value class BookSerializer (serializers.Serializer): title = serializers.CharField(max_length=32 ,validators=[title_django,]) ...
validate 在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class BookSerializer (serializers.Serializer): title = serializers.CharField(max_length=32 ) price = serializers.IntegerField(required=False ) pub_date = serializers.DateField(required=False ) bread = serializers.IntegerField(label='阅读量' , max_value=2147483647 , min_value=-2147483648 , required=False ) bcomment = serializers.IntegerField(label='评论量' , max_value=2147483647 , min_value=-2147483648 , required=False ) def validate_title (self, value ): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的" ) return value def validate (self, data ): bread = data.get("bread" ) bcomment = data.get("bcomment" ) if bread < bcomment: raise serializers.ValidationError('阅读量小于评论量' ) return data
测试
1 2 3 4 5 bs = BookSerializer(data={"title" :"Django深入浅出" ,"bread" :100 ,"bcomment" :200 ,"publish_id" :1 }) bs.is_valid() False bs.errors {'non_field_errors' : [ErrorDetail(string='阅读量小于评论量' , code='invalid' )]}
validators 在字段中添加validators选项参数,也可以补充验证行为,如
1 2 3 4 5 6 7 8 def about_django (value ): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的" ) class BookSerializer (serializers.Serializer): title = serializers.CharField(max_length=32 , validators=[about_django]) price = serializers.IntegerField(required=False ) pub_date = serializers.DateField(required=False )
测试:
1 2 3 4 5 6 from sers.sers import BookSerializerdata = {'btitle' : 'python' } serializer = BookSerializer(data=data) serializer.is_valid() serializer.errors
反序列化-保存数据 前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
可以通过实现create()和update()两个方法来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class BookInfoSerializer (serializers.Serializer): """图书数据序列化器""" ... def create (self, validated_data ): """新建""" return Book(**validated_data) def update (self, instance, validated_data ): """更新,instance为要更新的对象实例""" instance.btitle = validated_data.get('btitle' , instance.btitle) instance.bpub_date = validated_data.get('bpub_date' , instance.bpub_date) instance.bread = validated_data.get('bread' , instance.bread) instance.bcomment = validated_data.get('bcomment' , instance.bcomment) return instance
如果需要在返回数据对象的时候,也将数据保存到数据库中,则可以进行如下修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class BookInfoSerializer (serializers.Serializer): """图书数据序列化器""" ... def create (self, validated_data ): """新建""" return Book.objects.create(**validated_data) def update (self, instance, validated_data ): """更新,instance为要更新的对象实例""" instance.title = validated_data.get('title' , instance.title) instance.price = validated_data.get('price' , instance.price) instance.pub_date = validated_data.get('pub_date' , instance.pub_date) instance.save() return instance
实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
1 book = serializer.save()
如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。
1 2 3 4 5 6 7 8 9 from django.urls import path,re_path ,includefrom sers.views import BookView,BookDetailViewurlpatterns = [ path('books/' , BookView.as_view()), re_path('books/(?P<pk>\d+)/' , BookDetailView.as_view()), ]
1 2 3 # 序列化器 # 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer # 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
4.附加说明 1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到
1 2 serializer.save(owner=request.user)
2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
1 2 serializer = CommentSerializer(comment, data={'content' : u'foo bar' }, partial=True )
序列化与反序列化简单应用 1 2 3 4 5 /book/ GET 查看所有资源,返回所有资源 /book/ POST 添加资源,返回添加资源 /book/1 GET 查看某个资源,返回这一个资源 /book/1 PUT 编辑某个资源,返回编辑之后的这个资源 /book/1 DELETE 查看某个资源,返回空
models.py
1 2 3 4 5 6 7 from django.db import modelsclass Book (models.Model): title = models.CharField(max_length=32 ,verbose_name="书籍名称" ) price = models.IntegerField(verbose_name="价格" , null=True ) pub_date = models.DateField(verbose_name="出版日期" )
1 2 3 # 生成数据库 python manage.py makemigrations python manage.py migrate
1 2 3 4 5 6 # 进入当前虚拟环境 python控制台 新建2条数据 >> from sers.models import Book >> Book.objects.create(title="西游记",price="199",pub_date="2012-12-12") <Book: Book object (1)> >> Book.objects.create(title="水浒传",price="299",pub_date="2011-11-12") <Book: Book object (2)>
我们想为Book模型类提供一个序列化器,可以定义如下:
serializers.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from rest_framework import serializersfrom .models import Bookclass BookSerializers (serializers.Serializer): title = serializers.CharField(max_length=32 ) price = serializers.IntegerField(required=False ) date = serializers.DateField(source="pub_date" ) def create (self, validated_data ): new_book = Book.objects.create(**self.validated_data) return new_book def update (self, instance, validated_data ): Book.objects.filter (pk=instance.pk).update(**validated_data) updated_book = Book.objects.get(pk=instance.pk) return updated_book
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
1 2 3 4 5 6 7 8 path("sers/" , include("sers.urls" )), from django.urls import path,re_pathfrom sers import viewspath("book/" , views.BookView.as_view()), path("book/<int:id>/" , views.BookDetailView.as_view())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom django.http import Http404from .models import Bookfrom .serializers import BookSerializersclass BookView (APIView ): def get (self, request ): book_list = Book.objects.all () serializer = BookSerializers(instance=book_list, many=True ) ''' serializer 做了些什么 temp = [] for obj in book_list: d = {} d[title] = obj.title d[price] = obj.price d[pub_date] = obj.pub_date temp.append(d) ''' return Response(serializer.data) def post (self, request ): print ("data" , request.data) serializer = BookSerializers(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) else : return Response(serializer.errors) class BookDetailView (APIView ): def _check_book_exists (self, id ): if not Book.objects.filter (pk=id ).exists(): raise Http404() def get (self, request, id ): self._check_book_exists(id ) book = Book.objects.get(pk=id ) serializer = BookSerializers(instance=book, many=False ) return Response(serializer.data) def put (self, request, id ): self._check_book_exists(id ) update_book = Book.objects.get(pk=id ) serializer = BookSerializers(instance=update_book, data=request.data, many=False ) if serializer.is_valid(): serializer.save() return Response(serializer.data) else : return Response(serializer.errors) def delete (self, request, id ): self._check_book_exists(id ) Book.objects.get(pk=id ).delete() return Response()
BookView 类
get 方法:获取所有书籍的QuerySet
对象。 使用BookSerializers
序列化器将查询集序列化为JSON格式。 返回序列化后的数据作为HTTP响应。 post 方法:获取客户端提交的POST数据(通常是JSON格式)。 使用BookSerializers
序列化器进行反序列化(即验证数据)。 如果数据有效,调用序列化器的save()
方法将数据保存到数据库。 返回序列化后的新创建的数据或错误消息。 BookDetailView 类
_check_book_exists方法
定义了一个名为 _check_book_exists
的辅助方法,检查该 ID 对应的书籍是否存在,如果不存在,它会抛出一个 Http404
异常,这是 Django 的一个标准异常,用于处理 404 错误 使用 raise Http404()
是合适的,并且 DRF 也会正确处理这个异常 注意,虽然这里使用了异常处理,但这不是装饰器。异常是 Python 中的一种控制流机制,用于处理异常情况,这里使用 Http404
异常来优雅地处理书籍不存在的情况,在视图方法中调用辅助方法来得清晰和直接 如果你有更好的dispatch
重写方法,你也可以重写dispatch
来替代_check_book_exists
get 方法:
根据主键获取单个书籍对象。 使用BookSerializers
序列化器将书籍对象序列化为JSON格式。 返回序列化后的数据作为HTTP响应。 put 方法:
根据主键获取要更新的书籍对象。 使用BookSerializers
序列化器进行反序列化(更新数据)。 如果数据有效,调用序列化器的save()
方法更新数据库中的数据。 返回序列化后的更新后的数据或错误消息。 在PUT
请求(或类似的更新请求)中,你既需要instance
参数,也需要data
参数。这是因为:instance
参数用于指定你想要更新的数据库对象。这通常是通过查询数据库得到的现有对象。data
参数则用于传入客户端发送的更新数据,这通常是一个包含新字段值的字典。序列化器使用这两个参数来执行以下操作:使用instance
参数中的对象作为更新的基础。 使用data
参数中的新数据来验证和更新instance
对象。 delete 方法:
根据主键删除书籍对象。 返回一个空的HTTP响应(虽然在实际应用中,通常返回状态码和消息来确认删除操作) 在put
方法中,首先通过Book.objects.get(pk=id)
获取到现有的书籍对象(update_book
),然后将这个对象作为instance
参数传入序列化器。同时,你将客户端发送的更新数据(request.data
)作为data
参数传入。这样,序列化器就能知道它应该更新哪个对象(instance
),以及应该使用哪些新数据来更新(data
)。
最后,通过调用serializer.is_valid()
,你可以确保客户端发送的数据是有效的,并且符合你的序列化器定义的字段和验证规则。如果验证通过,你就可以安全地调用serializer.save()
来保存更新到数据库了。
知识点梳理: APIView:APIView
是Django REST framework提供的一个基类,用于构建API的视图。它包含了一些用于处理HTTP请求和响应的方法。 Response:Response
是Django REST framework中用于构建HTTP响应的类。它接收数据(通常是序列化后的数据)和状态码,然后返回一个HTTP响应。 Model与QuerySet:Book
是一个Django模型,代表数据库中的书籍数据。Book.objects.all()
返回一个包含所有书籍的QuerySet
对象。Book.objects.get(pk=id)
根据主键获取单个书籍对象。 Serializer:序列化器(Serializer)用于将复杂的数据类型(如Django模型或查询集)转换为Python数据类型,以便可以轻松地渲染为JSON、XML或其他内容类型。 在你的代码中,BookSerializers
是一个序列化器,用于处理Book
模型的数据。 HTTP方法:GET
: 用于从服务器请求数据。POST
: 用于向服务器提交数据,通常用于创建新记录。PUT
: 用于更新服务器上的数据。DELETE
: 用于删除服务器上的数据。 数据校验:序列化器可以执行数据校验。当调用serializer.is_valid()
时,序列化器会检查传入的数据是否符合定义的字段和验证规则。 序列化与反序列化:序列化:将复杂的Python对象转换为Python数据类型或JSON格式,以便可以传输或存储。 反序列化:将JSON或其他格式的数据转换为Python对象,以便可以在程序中处理。 GET http://127.0.0.1:8000/sers/book/
1 2 3 4 5 6 7 8 9 10 11 12 [ { "title" : "西游记" , "price" : 199 , "date" : "2012-12-11" } , { "title" : "水浒传" , "price" : 299 , "date" : "2011-11-12" } ]
GET http://127.0.0.1:8000/sers/book/2/
1 2 3 4 5 { "title" : "水浒传" , "price" : 299 , "date" : "2011-11-12" }
GET http://127.0.0.1:8000/sers/book/111/
1 2 3 { "detail" : "Not found." }
PUT http://127.0.0.1:8000/sers/book/2/
PUT http://127.0.0.1:8000/sers/book/111/
1 2 3 { "detail" : "Not found." }
DELETE http://127.0.0.1:8000/sers/book/3/
返回空
DELETE http://127.0.0.1:8000/sers/book/111/
1 2 3 { "detail" : "Not found." }
案例:前端想要的是date
字段不是pub_date
字段,但是自己的模型类是pub_date
1 2 3 4 5 class BookSerializers (serializers.Serializer): title = serializers.CharField(max_length=32 ) price = serializers.IntegerField() date = serializers.DateField(source="pub_date" )
这里的date = serializers.DateField(source="pub_date")
意味着在序列化时,Book
模型的pub_date
字段的值会被用来填充序列化器中的date
字段。同样地,在反序列化时,当你为date
字段提供一个值时,这个值会被用来更新Book
模型的pub_date
字段。
简而言之,source
参数允许你指定一个不同的字段名或方法名作为序列化或反序列化的来源。这在处理模型字段和API字段之间命名不一致的情况时非常有用。
1 2 3 4 5 6 7 8 9 10 11 12 [ { "title" : "西游记" , "price" : 199 , "date" : "2012-12-11" } , { "title" : "水浒传111" , "price" : 119 , "date" : "2016-12-11" } ]
模型类序列化器 如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
基于模型类自动生成一系列字段 基于模型类自动为Serializer生成validators,比如unique_together 包含默认的create()和update()的实现 1.定义 我们之前的序列化器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from rest_framework import serializersfrom .models import Bookclass BookSerializers (serializers.Serializer): title = serializers.CharField(max_length=32 ) price = serializers.IntegerField(required=False ) date = serializers.DateField(source="pub_date" ) def create (self, validated_data ): new_book = Book.objects.create(**self.validated_data) return new_book def update (self, instance, validated_data ): Book.objects.filter (pk=instance.pk).update(**validated_data) updated_book = Book.objects.get(pk=instance.pk) return updated_book
用模型类后的序列化器
1 2 3 4 5 class BookSerializer (serializers.ModelSerializer): """图书数据序列化器""" class Meta : model = Book fields = '__all__'
model 指明参照哪个模型类 fields 指明为模型类的哪些字段生成 不需要再写 update()
和 create()
方法,这得益于 Django REST framework 的强大功能。序列化器内部已经实现了基本的 create()
和 update()
方法,这些方法基于你提供的模型和字段信息自动处理模型的创建和更新
我们可以在python manage.py shell中查看自动生成的BookSerializer的具体实现
注意,只有序列化器改为BookSerializer,其他部分都没动
2.指定字段 使用fields 来明确字段,__all__
表名包含所有字段,也可以写明具体哪些字段,如 1 2 3 4 5 class BookSerializers (serializers.ModelSerializer): class Meta : model = Book fields = ["title" ,"price" ]
使用exclude 可以明确排除掉哪些字段 1 2 3 4 class BookSerializers (serializers.ModelSerializer): class Meta : model = Book exclude = ["price" ]
3.重命名字段名 1 2 3 4 5 6 7 8 9 10 class BookSerializers (serializers.ModelSerializer): date = serializers.DateField(source="pub_date" ) class Meta : model = Book exclude = ["pub_date" ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 # __all__ [ { "id" : 1 , "date" : "2012-12-11" , "title" : "西游记" , "price" : 199 , "pub_date" : "2012-12-11" } , { "id" : 2 , "date" : "2016-12-11" , "title" : "水浒传111" , "price" : 119 , "pub_date" : "2016-12-11" } ] # exclude [ { "id" : 1 , "date" : "2012-12-11" , "title" : "西游记" , "price" : 199 } , { "id" : 2 , "date" : "2016-12-11" , "title" : "水浒传111" , "price" : 119 } ]
指明只读字段 可以通过read_only_fields 指明只读字段,即仅用于序列化输出的字段
1 2 3 4 5 class BookSerializers (serializers.ModelSerializer): class Meta : model = Book fields = '__all__' read_only_fields = ["title" ,'price' ]
4.添加一些额外的验证规则 我们可以使用extra_kwargs 参数为ModelSerializer添加或修改原有的选项参数
现在,你希望创建一个序列化器来序列化和反序列化这个模型,同时你希望对某些字段添加一些额外的验证规则。你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 from rest_framework import serializersfrom .models import Bookclass BookSerializer (serializers.ModelSerializer): class Meta : model = Book fields = ('title' , 'price' , 'pub_date' ) extra_kwargs = { 'title' : {'max_length' : 32 }, 'price' : {'required' : False , 'min_value' : 0 }, 'pub_date' : {'required' : True }, }
仅供参考 自定义反序列化字段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class PublishModelSerializer (serializers.ModelSerializer): re_name = serializers.CharField(write_only=True ) class Meta : model = models.Publish fields = ('name' , 're_name' , 'address' ) def validate (self, attrs ): name = attrs.get('name' ) re_name = attrs.pop('re_name' ) if name != re_name: raise serializers.ValidationError({'re_name' : '确认名字有误' }) return attrs
模型类中自定义序列化深度 1 2 3 4 5 6 7 8 class Book (BaseModel ): @property def publish_detail (self ): from . import serializers data = serializers.PublishModelSerializer(self.publish).data return data
接口操作总结 路由层:api/url.py
1 2 3 4 5 6 7 from django.conf.urls import urlfrom . import viewsurlpatterns = [ url(r'^v3/books/$' , views.BookV3APIView.as_view()), url(r'^v3/books/(?P<pk>.*)/$' , views.BookV3APIView.as_view()), ]
模型层:api/models.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 from django.db import modelsfrom utils.model import BaseModelclass Book (BaseModel ): name = models.CharField(max_length=64 ) price = models.DecimalField(max_digits=5 , decimal_places=2 ) img = models.ImageField(upload_to='img' , default='img/default.png' ) publish = models.ForeignKey(to='Publish' , null=True , related_name='books' , db_constraint=False , on_delete=models.DO_NOTHING, ) authors = models.ManyToManyField(to='Author' , null=True , related_name='books' , db_constraint=False , ) @property def publish_name (self ): return self.publish.name @property def authors_info (self ): author_list = [] for author in self.authors.all (): author_list.append({ 'name' : author.name, 'age' : author.age, 'mobile' : author.detail.mobile }) return author_list @property def publish_bac (self ): from . import serializers data = serializers.PublishModelSerializer(self.publish).data return data class Meta : db_table = 'old_boy_book' verbose_name = '书籍' verbose_name_plural = verbose_name def __str__ (self ): return self.name class Publish (BaseModel ): name = models.CharField(max_length=64 ) address = models.CharField(max_length=64 ) class Meta : db_table = 'old_boy_publish' verbose_name = '出版社' verbose_name_plural = verbose_name def __str__ (self ): return self.name class Author (BaseModel ): name = models.CharField(max_length=64 ) age = models.IntegerField() @property def mobile (self ): return self.detail.mobile class Meta : db_table = 'old_boy_author' verbose_name = '作者' verbose_name_plural = verbose_name def __str__ (self ): return self.name class AuthorDetail (BaseModel ): mobile = models.CharField(max_length=11 ) author = models.OneToOneField(to='Author' , null=True , related_name='detail' , db_constraint=False , on_delete=models.CASCADE ) class Meta : db_table = 'old_boy_author_detail' verbose_name = '作者详情' verbose_name_plural = verbose_name def __str__ (self ): return '%s的详情' % self.author.name
序列化层:api/serializers.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class BookV3ListSerializer (serializers.ListSerializer): def update (self, instance, validated_data ): ''' :param instance: [book_obj1, ..., book_obj2] :param validated_data: [{更新数据的字段}, ..., {更新数据的字段}] :return: [book_new_obj1, ..., book_new_obj2] ''' for index, obj in enumerate (instance): for attr, value in validated_data[index].items(): if hasattr (obj, attr): setattr (obj, attr, value) obj.save() return instance class BookV3ModelSerializer (serializers.ModelSerializer): class Meta : model = models.Book fields = ('name' , 'price' , 'publish' , 'authors' , 'img' , 'publish_name' , 'authors_info' ) list_serializer_class = BookV3ListSerializer extra_kwargs = { 'publish' : { 'required' : True , 'write_only' : True }, 'authors' : { 'required' : True , 'write_only' : True }, 'img' : { 'read_only' : True } } def validate_name (self, value ): if 'sb' in value: raise serializers.ValidationError('书名有敏感词汇' ) return value def validate (self, attrs ): name = attrs.get('name' ) publish = attrs.get('publish' ) if models.Book.objects.filter (name=name, publish=publish): raise serializers.ValidationError({'book' : '书籍以存在' }) return attrs
视图层:api/views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 class BookV3APIView (APIView ): def get (self, request, *args, **kwargs ): pk = kwargs.get('pk' ) if pk: book_obj = models.Book.objects.filter (is_delete=False , pk=pk).first() if not book_obj: return APIResponse(1 , 'pk error' ) book_ser = serializers.BookV3ModelSerializer(book_obj) return APIResponse(0 , 'ok' , results=book_ser.data) book_query = models.Book.objects.filter (is_delete=False ).all ().order_by('-id' ) book_ser = serializers.BookV3ModelSerializer(book_query, many=True ) return APIResponse(0 , 'ok' , results=book_ser.data) def post (self, request, *args, **kwargs ): request_data = request.data if isinstance (request_data, dict ): data = [request_data, ] elif isinstance (request_data, list ): data = request_data else : return APIResponse(1 , '数据格式有误' ) book_ser = serializers.BookV3ModelSerializer(data=data, many=True ) if book_ser.is_valid(): book_obj_list = book_ser.save() return APIResponse(0 , 'ok' , results=serializers.BookV3ModelSerializer(book_obj_list, many=True ).data ) else : return APIResponse(1 , '添加失败' , results=book_ser.errors) """ 1)先确定要更新的对象 主键们 与 数据们 2)通过校验数据库剔除 已删除的对象 与 不存在的对象 主键们 => 剔除过程 => 可以修改的对象们 数据们 => 剔除过程 => 可以修改的对象们对应的数据们 3)反序列化及校验过程 通过 => save() 完成更新 失败 => ser_obj.errors 返回 """ def patch (self, request, *args, **kwargs ): pk = kwargs.get('pk' ) request_data = request.data if pk: if not isinstance (request_data, dict ): return APIResponse(1 , '单改数据有误' ) pks = [pk, ] data = [request_data, ] elif isinstance (request_data, list ): try : pks = [] for dic in request_data: pks.append(dic.pop('pk' )) data = request_data except : return APIResponse(1 , '群改数据有误' ) else : return APIResponse(1 , '数据格式有误' ) book_query = [] filter_data = [] for index, pk in enumerate (pks): book_obj = models.Book.objects.filter (is_delete=False , pk=pk).first() if book_obj: book_query.append(book_obj) filter_data.append(data[index]) book_ser = serializers.BookV3ModelSerializer(instance=book_query, data=filter_data, many=True , partial=True ) if book_ser.is_valid(): book_obj_list = book_ser.save() return APIResponse(1 , 'ok' , results=serializers.BookV3ModelSerializer(book_obj_list, many=True ).data ) else : return APIResponse(1 , '更新失败' , results=book_ser.errors) def delete (self, request, *args, **kwargs ): pk = kwargs.get('pk' ) if pk: pks = [pk] else : pks = request.data.get('pks' ) if not pks: return APIResponse(1 , '删除失败' ) book_query = models.Book.objects.filter (is_delete=False , pk__in=pks) if not book_query.update(is_delete=True ): return APIResponse(1 , '删除失败' ) return APIResponse(0 , '删除成功' )