从数据库中取出数据后,虽然不能直接将queryset和model对象以及datetime类型序列化,但均可以将其转化成能够序列化的类型,再序列化。python
功能需求都能作到,可是比较麻烦,每次须要手动实现。且取出的数据还须要进行转化,好比某些字段在存储时将汉字转化成数字,取出来后要将数字转化成汉字,这都是须要每次手动操做。数据库
做用:json
models.py函数
class Book(models.Model): title = models.CharField(max_length=32, verbose_name="图书名称") CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) category = models.IntegerField(choices=CHOICES, verbose_name="图书的类别") pub_time = models.DateField(verbose_name="图书的出版日期") publisher = models.ForeignKey(to="Publisher", on_delete=None) author = models.ManyToManyField(to="Author") def __str__(self): return self.title class Meta: verbose_name_plural = "Book" db_table = verbose_name_plural class Publisher(models.Model): title = models.CharField(max_length=32, verbose_name="出版社的名称") def __str__(self): return self.title class Meta: verbose_name_plural = "Publisher" db_table = verbose_name_plural class Author(models.Model): name = models.CharField(max_length=32, verbose_name="做者的姓名") def __str__(self): return self.name class Meta: verbose_name_plural = "Author" db_table = verbose_name_plural
views.pypost
from .seriallzers import BookSeriallzer # 自定义的问加减 class BookView(APIView): def get(self, request): book_list = Book.objects.all() ret = BookSeriallzer(book_list, many=True) # 序列化过程 return Response(ret.data) def post(self, request): print("数据",request.data) serializer = BookSeriallzer(data=request.data) # 反序列化 if serializer.is_valid(): print("验证经过") serializer.save() # save()方法保存数据库,须要在序列化器里自定义create方法 return Response(serializer.data) else: return Response(serializer.errors)
seriallzers.pyui
from rest_framework import serializers def my_validate(value): if "mingan" in value.lower(): raise serializers.ValidationError("不能含有敏感信息") else: return value class BookSeriallzer(serializers.Serializer): id = serializers.IntegerField(required=False) # required False的意思是 反序列化(存库)的时候非必需 title = serializers.CharField(max_length=32, validators=[my_validate]) # 此种验证方式比局部钩子优先级高 CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True) # 只在序列化(读库)的时候起做用 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # 只在反序列化的时候用(存库) pub_time = serializers.DateField() publisher = PublishSeriallzer(read_only=True) publisher_id = serializers.IntegerField(write_only=True) author = AuthorSeriallzer(many=True, read_only=True) # 经过many参数来区别是普通外键仍是多对多关系 author_list = serializers.ListField(write_only=True) def create(self, validated_data): book = Book.objects.create(title=validated_data["title"],category=validated_data["w_category"], pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"]) book.author.add(*validated_data["author_list"]) return book def update(self, instance, validated_data): "instance是views函数中传来的book_obj" instance.title = validated_data.get("title", instance.title) # 若是已验证的数据中没有title字段,不更新,不会报错 instance.category = validated_data.get("w_category", instance.category) instance.pub_time = validated_data.get("pub_time", instance.pub_time) instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id) if validated_data.get("author_list"): instance.author.set(validated_data["author_list"]) # 更新多对多字段 instance.save() return instance def validate_title(self, value): "局部钩子,自定义对title字段的验证" if "python" not in value.lower(): raise serializers.ValidationError("标题必须含有python") return value def validate(self, attrs): "全局的校验规则,能够进行多字段联合校验" if attrs["w_category"] == 1 and attrs["publisher_id"] == 1: return attrs else: raise serializers.ValidationError("分类以及标题不符合要求") 验证顺序:validators属性 -> 局部钩子 -> 全局钩子
这样就实现了 序列化 和 反序列化的过程,包括特殊字段(时间类型、外键关系、chioce)转化以及存库时的验证。spa
须要说明的是:rest
可是,序列化和反序列化的过程很是不简洁,写了太多的东西。对象
ModelSerializer类能够与ORM映射表结合,自动对应序列化关系。blog
from .models import Book, Publisher class BookSeriallzer(serializers.ModelSerializer): category_display = serializers.SerializerMethodField() # 读取数据时的字段名(与"category"区分开来,下同) publisher_info = serializers.SerializerMethodField() # 配合 get_字段名() 钩子,自定义经过外键取出的字段 authors = serializers.SerializerMethodField() def get_category_display(self, obj): return obj.get_category_display() def get_publisher_info(self, obj): # obj 是每一个book对象 publisher_obj = obj.publisher return {"id": publisher_obj.id, "title": publisher_obj.title} # 只取出来本身想要的数据,不会有其余的冗余数据 def get_authors(self, obj): authors = obj.author.all() return [{"id": author.id, "name": author.name} for author in authors] class Meta: model = Book # 对应ORM表 # fields = ["id", "title", "pub_time", "category"] # 须要取出的字段 fields = "__all__" # 表示要取出全部字段 # depth = 1 # 序列化的外键层级。若是不规定此值,全部的外键字段都只是id。有个缺点:会取出外键对应的全部数据,很是冗余 extra_kwargs = { "category": {"write_only": True}, # “category”字段只写 "publisher": {"write_only": True}, "author": {"write_only": True} }
这样,咱们只须要将存取不一致的行为定义好便可,其它字段均可以自动对应好。很是方便。