有Django-JsonResponse序列化,为什么还要用DRF框架?
第一版:用.values JsonResponse来实现序列化
Json.dumps(book_list, ensure_ascii=False)方法不能序列化Date类型
JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii':False})可以序列化Date类型
如果有forienkey传的就是ID,就需要自己拼,这样代码会重复
如果用DjangoSerializer呢?
第二版:用django serializers实现序列化
from django.core import serializers
ret = serializers.serialize("json", book_list_queryset, ensure_ascii=False)
return HttpResponse(ret)
这样的数据外键依然是ID,依然需要自己拼,跟上面的差不多
第三版:用框架实现序列化
pip install djangorestframework
------------图书的增删改查-----------
图书列表: get请求 http://127.0.0.1:8000/serdemo/book/list
新增图书: post请求 http://127.0.0.1:8000/serdemo/book/list
图书详情:get请求 http://127.0.0.1:8000/serdemo/retrieve/<id>
修改图书:put请求 http://127.0.0.1:8000/serdemo/retrieve/<id>
models.py
from django.db import models 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 Publisher(models.Model): title = models.CharField(max_length=32, verbose_name="出版社的名称") def __str__(self): return self.title class Author(models.Model): name = models.CharField(max_length=32, verbose_name="作者的姓名") def __str__(self): return self.name
views.py
from rest_framework.views import APIView from rest_framework.response import Response from .models import Book # from .serializers import BookSerializer from .model_serializer import BookSerializer class BookView(APIView): def get(self, request): books_list = Book.objects.all() ret = BookSerializer(books_list, many=True) # 如果是单个对象就不加"many=True" return Response(ret.data) def post(self, request): serializer = BookSerializer(data=request.data) # 放在data里,表示是反序列化的数据 if serializer.is_valid(): serializer.save() print( serializer.data) # {'id': 22, 'category_display': 'Go', 'publisher_info': {'id': 1, 'title': '春风出版社'}, 'authors_list': [{'id': 3, 'name': '张三'}, {'id': 4, 'name': '李四'}], 'title': 'GO语言编程思想', 'pub_time': '2018-12-25'} print( serializer.validated_data) # OrderedDict([('title', 'GO语言编程思想'), ('category', 2), ('pub_time', datetime.date(2018, 12, 25)), ('publisher', <Publisher: 春风出版社>), ('author', [<Author: 张三>, <Author: 李四>])]) return Response(serializer.data) # 如果用serializer.validated_data会报错:"Publish不是JSON可序列化对象" else: return Response(serializer.errors) class BookEditView(APIView): def get(self, request, id): try: book_obj = Book.objects.get(id=id) except Exception as e: return Response({"error": e.__str__()}) ret = BookSerializer(book_obj) return Response(ret.data) def put(self, request, id): book_obj = Book.objects.get(id=id) # 第一个参数是要更新的对象,第二个参数是要更新的数据,第三个参数表示允许部分更新 serializer = BookSerializer(book_obj, data=request.data, partial=True) if serializer.is_valid(): serializer.save() # 要重写serializer中的update方法 return Response(serializer.validated_data) else: return Response(serializer.errors) def delete(self, request, id): book_obj = Book.objects.get(id=id) book_obj.delete() return Response("") ''' { "title": "GO语言编程思想", "w_category": 2, "pub_time": "2018-12-25", "publisher_id": 1, "author_list": [3,4] } '''
urls.py
from django.urls import path from . import views app_name = 'serdemo' urlpatterns = [ path("book/list", views.BookView.as_view()), path("retrieve/<int:id>", views.BookEditView.as_view()) ]
serializers.py
from rest_framework import serializers from .models import Book class PublisherSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=32) class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField(max_length=32) def my_validator(value): ''' 校验器,校验Book的title字段 :param value: :return: ''' if "fuck" in value.lower(): raise serializers.ValidationError("标题中不能有脏话") return value class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) # required=False,表示这个字段不校验 title = serializers.CharField(max_length=32, validators=[my_validator, ]) # 验证器的优先级比该字段的验证函数高 CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) # category序列化和反序列化不一样,read_only=True表示只序列化的时候用,后端传到前端是汉子 category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True) # write_only只是反序列化用,前端传到后端的是数字 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) pub_time = serializers.DateField() publisher = PublisherSerializer(read_only=True) publisher_id = serializers.IntegerField(write_only=True) author = AuthorSerializer(many=True, read_only=True) 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.title = validated_data.get("title", instance.title) instance.category = validated_data.get("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) author_list = validated_data.get("author_list") if author_list: instance.author.set(*author_list) instance.save() return instance def validate_title(self, value): ''' 钩子函数validate_字段,单独校验title :param value: :return: ''' if "python" not in value.lower(): raise serializers.ValidationError("标题中必须含有‘python’") return value def validate(self, attrs): w_category = attrs.get('w_category') publisher_id = attrs.get('publisher_id') if w_category == 1 and publisher_id == 1: return attrs else: raise serializers.ValidationError("分类及标题不符合要求") """ 反序列化的数据结构: { "title": "GO语言编程思想", "w_category": 2, "pub_time": "2018-12-25", "publisher_id": 1, "author_list": [3,4] } """
model_serializers.py
from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): ''' 使用ModelSerializer反序列化,只配置class Meta就能实现。 所以,只需要重写原字段的序列化功能就可以了,重写的时候序列化字段跟原字段不一样, 例如category改成category_display,如果跟原字段一样就都重写了,这里只重写原字段的序列化 同时,需要配置xx将原字段配置为只反序列化 所以,序列化用category_display,反序列化用category ''' category_display = serializers.SerializerMethodField(read_only=True) publisher_info = serializers.SerializerMethodField(read_only=True) authors_list = serializers.SerializerMethodField(read_only=True) def get_category_display(self, obj): return obj.get_category_display() def get_publisher_info(self, obj): # obj是序列化的每个Book对象,publiser是外键 publisher_obj = obj.publisher return {"id": publisher_obj.id, "title": publisher_obj.title} def get_authors_list(self, obj): # author是多对多 authors_queryset = obj.author.all() return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_queryset] class Meta: model = Book # fields = ["id", "title", "pub_time"] fields = "__all__" # 排序就列表分开写,不排序就写__all__ # depth = 1 # 根据外键关系向下找一层,这样把外键所有字段都查出来,method_field extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True}, "author": {"write_only": True} }