原生serializer的使用
from django.core.serializers import serialize class StudentView(APIView): def get(self, request): origin_students = Student.objects.all() serialized_students = serialize("json", origin_students) return HttpResponse(serialized_students)
DRF解析器组件
使用:
#1. 引入模块 from rest_framework.views import APIView #2. 继承APIView class LoginView(APIView): parser_classes = [FormParser] def get(self, request): return render(request, 'parserver/login.html') # .3. 直接request.data就可以获取json数据 def post(self, request): # request是被drf封装的新对象,基于django的request # request.data是一个property,用于对数据进行校验 # request.data最后会找到self.parser_classes中的解析器 # 来实现对数据进行解析 print(request.data) # {'username': 'alex', 'password': 123} return JsonResponse({"status_code": 200, "code": "OK"})
解释器组件源码流程 ![](https://img2018.cnblogs.com/blog/1450173/201812/1450173-20181211213200723-2099959718.png)
序列化组件
定义几个model
from django.db import models # Create your models here. class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=32) publishDate = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE) authors = models.ManyToManyField(to="Author") def __str__(self): return self.title
设计url,请求接口
GET接口
url:
from django.urls import re_path from serializers import views urlpatterns = [ re_path(r'books/$', views.BookView.as_view()) ]
新建一个名为app_serializers.py的模块,将所有的序列化的使用集中在这个模块里面,对程序进行解耦:
from rest_framework import serializers from .models import Book
#1.定义序列化类 class BookSeriazlizer(seriazlizers.Serializer):
#2.定义需要返回的字段(字段类型可以与model中的类型不一致,参数也可以调整),
字段名称必须与model中的一致
title = serializers.CharField(max_length=128)
publish_date = serializers.DateTimeField()
price = serializers.DecimalField(max_digits=5, decimal_places=2) publish = serializers.CharField(max_length=32) authors = serializers.CharField(max_length=32)
视图类,使用序列化组件
from rest_framework.views import APIView from rest_framework.response import Response from .models import Book from .app_serializer import BookSerializer class BookView(APIView): def get(self,request):
#3. GET接口逻辑中,获取QuerySet origin_books = Book.objects.all()
#4.开始序列化 ,many默认为False,若返回的数据是个多个对象集合,需改为True serialized_books = BookSerializer(origin_books,many=True) return Response(serialized_books.data)
下面是通过POSTMAN请求该接口后的返回的测试数据,除ManyToManyField字段不是想要的外,其他的都没有任何问题:
[ { "title": "Python入门", "publishDate": null, "price": "119.00", "publish": "浙江大学出版社", "authors": "serializers.Author.None" }, { "title": "Python进阶", "publishDate": null, "price": "128.00", "publish": "清华大学出版社", "authors": "serializers.Author.None" } ]
若当字段定义为多个参数时,比如authors.all,取出来的结果将是一个querset,对前端来书,这样的数据不太友好,稍微改进下
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField() publish = serializers.CharField() publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_email = serializers.CharField(max_length=32, read_only=True, source='publish.email') # authors = serializers.CharField(max_length=32, source='authors.all') authors_list = serializers.SerializerMethodField() def get_authors_list(self, authors_obj): authors = list() for author in authors_obj.authors.all(): authors.append(author.name) return authors # 注:get_必须与字段名称一致,否则会报错
POST接口设计
def post(self, request): verified_data = BookSerializer(data=request.data) if verified_data.is_valid(): book = verified_data.save() # 可写字段通过序列化添加成功之后需要手动添加只读字段 authors = Author.objects.filter(nid__in=request.data['authors']) book.authors.add(*authors) return Response(verified_data.data) else: return Response(verified_data.errors)
多对多字段同样需要自己手动来获取
def get_authors_list(self, book_obj): author_list = list() for author in book_obj.authors.all(): author_list.append(author.name) return author_list def create(self, validated_data): # {'title': 'Python666', 'price': Decimal('66.00'), 'publish': '2'} validated_data['publish_id'] = validated_data.pop('publish') book = Book.objects.create(**validated_data) return book def update(self, instance, validated_data): # 更新数据会调用该方法 instance.title = validated_data.get('title', instance.title) instance.publishDate = validated_data.get('publishDate', instance.publishDate) instance.price = validated_data.get('price', instance.price) instance.publish_id = validated_data.get('publish', instance.publish.nid) instance.save() return instance
感觉还是有点麻烦,若字段很多,写序列化也是一种负担,更加简单的方式如下:
# 继承ModelSerializer class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('title', 'price', 'publish', 'authors', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { 'publish': {'write_only': True}, 'authors': {'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset开始循环 [{}, {}, {}, {}] authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors
详细步骤:
- 继承ModelSerializer:不再继承Serializer
- 添加extra_kwargs类变量:extra_kwargs = {‘publish’: {‘write_only’: True}}