rest_framework序列化之Serialzier
***记得先在apps里面注册rest_framework***
models.py
class Book(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2) publish_time = models.DateField() category = models.IntegerField(choices=((1, "文学类"), (2, "艺术类"), (3, "其他类")), null=True) authors = models.ManyToManyField(to="Author") publish = models.ForeignKey(to="Publish", null=True) class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField()
urls.py
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^books/(?P<id>d*)/', views.BookDetail.as_view()), url(r'^books/$', views.Book.as_view()), url(r'^authors/$', views.Author.as_view()), ]
app02serializer.py
class BookSerializer(serializersSerializer): name = serializers.CharField() price = serializers.CharField() publish_time = serializers.DateField() category = serializers.SerializerMethodField() # source可以指定摸一个具体字段(),也可以指定为一个方法 # publish = serializers.CahrField(source="publish.name") # category = serializers.CharField(source="get_category_display") # 使用SerializerMethodField,后面必须跟一个方法(get_字段名) publish = serializers.SerializerMethodField() authors = serializers.SerializerMethodField() def get_category(self, obj): return obj.get_category_display() def get_publish(self, obj): return PublishSerializer(obj.publish).data def get_authors(self, obj): res = AuthorSerializer(obj.authors.all(), many=True) return res.data # 使用Serializer序列化,添加数据时需重写create方法 def create(self, validated_data): authors = validated_data.pop('authors') obj = models.Book.objects.create(**validated_data) obj.authors.add(*authors) return obj
views.py
from rest_framework.views import APIView from rest_framework.response import Response from app02 import models from app02 import app02serializer def post(self, request): back_dic = {"code": 100, "msg": "新增成功"} book_servializer = app02serializer.BookSerializer(data=request.data) if book_servializer.is_valid(): print(book_servializer.validated_data) # 序列化使用Serializer时,添加数据需要使用重写的create方法 book_servializer.create(book_servializer.validated_data) return Response(back_dic)
rest_framework序列化之ModelSerialzier
app02serializer.py
from app02 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ("__all__") # fields=['id','name','authors','publish'] # exclude=["name", ] # 与fields不能同时使用 # depth = 1 # 深度控制 class PublishSerializer(serializers.ModelSerializer): class Meta: model = models.Publish fields = "__all__" class AuthorSerializer(serializers.ModelSerializer): class Meta: model = models.Author fields = "__all__"
views.py
from rest_framework.views import APIView from rest_framework.response import Response from app02 import models from app02 import app02serializer # 由于每个视图类中都会有get方法,因此可抽取出放到一个基类中,其他方法一样 class Get(object): def get(self, request, *args, **kwargs): response = {"code": 100, "msg": "查看成功"} book_list = self.cls.objects.all() # 序列化多个对象需传入参数many data = self.ser(instance=book_list, many=True).data response["data"] = data return Response(response) class Book(APIView, Get): cls = models.Book ser = app02serializer.BookSerializer def post(self, request, *args, **kwargs): response = {"code": 100, "msg": "新增成功"} book_serializer = app02serializer.BookSerializer(data=request.data) if book_serializer.is_valid(): book_serializer.save() else: response["code"] = 101 response["msg"] = book_serializer.errors return Response(response) class BookDetail(APIView): def get(self, request, id, *args, **kwargs): response = {"code": 100, "msg": "查看成功"} book_obj = models.Book.objects.filter(pk=id).first() book_serializer = app02serializer.BookSerializer(instance=book_obj) response["data"] = book_serializer.data return Response(response) def put(self, request, id, *args, **kwargs): response = {"code": 100, "msg": "修改成功"} book_obj = models.Book.objects.filter(pk=id).first() # 更新数据需传入对象本身以及数据(包括未更新的数据) book_serializer = app02serializer.BookSerializer(instance=book_obj, data=request.data) if book_serializer.is_valid(): book_serializer.save() else: response["code"] = 102 response["msg"] = book_serializer.errors return Response(response) def delete(self, request, id, *args, **kwargs): response = {"code": 100, "msg": "删除成功"} models.Book.objects.filter(pk=id).delete() return Response(response) class Author(APIView, Get): cls = models.Author ser = app02serializer.AuthorSerializer
钩子函数
# 局部钩子 def validate_title(self, value): from rest_framework import exceptions raise exceptions.ValidationError('看你不顺眼') return value # 全局 def validate(self, attrs): from rest_framework import exceptions if attrs.get('password') == attrs.get('confirm_password'): return attrs else: raise exceptions.ValidationError('不想等啊')
序列化组件源码分析
校验源码部分
调用了 序列化对象.is_valid方法才走校验 ----> 内部走了self.run_validation方法(找该方法一定要从根上找) ---> Serializer类中找到了run_validation方法
---> 重点的地方:self.to_internal_value(局部钩子)/self.validate(全局钩子) --->
Serializer类中找到了to_internal_value,去对象内部反射validate_字段名的方法,如果不为None,直接执行,于是就执行了咱们自己写的局部校验的函数
序列化类实例化many参数相关
many=True的时候,生成的是列表中放了一个个的序列号化对象
many=False 的时候,生成的是一个序列化对象
序列化对象.data相关
执行Serializer内的data方法--->又执行了父类(BaseSerializer)的data方法--->执行self.to_representation(其实执行的是Serializer内的to_representation方法)
最终执行的是每个字段对象的get_attribute方法--->找字段对象的该方法-->在Field中找到了该方法
--->执行了get_attribute(instance, self.source_attrs)--->self.source_attrs:每个字段source后面指定的根据.切分后的列表(publish.name:就会被分成[publish,name])
如果是方法会执行方法,如果是字段,通过反射取出值