DRF serializers小结
django settings文件查找顺序
django查询变量的顺序是先从用户的settings里面查找,然后在global_settings中查找,如果用户desettings文件中找到了,则不会继续查找global_settings中的配置信息。
django原生的serializer
from django.db import models
# Create your models here.
class Courses(models.Model):
title = models.CharField(max_length=32)
description = models.CharField(max_length=128)
class CoursesView(View):
def get(self, request):
courses = list()
for item in Courses.objects.all():
course = {
"title": item.title,
"description": item.description
}
courses.append(course)
return HttpResponse(json.dumps(courses, ensure_ascii=False))
通过上面的方式,我们定义了符合规范的返回数据,加上符合规范的url,我们完成了手动完成了REST开发,但是效率不高。
from django.core.serializers import serialize
class StudentView(APIView):
def get(self, request):
origin_Student = Student.objects.all()
serialized_students = serialize("json", origin_students)
return HttpResponse(serialized_students)
使用方法非常简单,导入模块之后,价格需要的格式和queryset传给serialize进行序列化,然后返回序列化后的数据。
如果你的项目仅仅只需要序列化一部分数据,不需要用到诸如认证、权限等其他功能,可以使用django原生的serializer,否则建议使用DRF。
解析器组件
from django.http import JsonResponse
from rest_framework.view import APIView
from rest_framework.parsers import JSONParser, FormParser
# Create your views here.
class LoginView(APIView):
def get(self, request):
return render(request, 'parserver/logoin.html')
def post(self, request):
# request 是被drf封装的新的对象,是基于django的request
# request.data是一个property,用于对数据进行校验
# request.data最后会找到self.parser_classes中的解析器来实现对数据进行解析
print(requet.data) # {'username':'Gavin', 'password':123}
return JsonResponse({'status_code':200, 'code':'ok'})
使用步骤如下:
- from rest_framework.views import APIView
- 继承APIView
- 直接使用request.data就可以获取Json数据
如果只需要解析Json数据,不允许其他类型的数据请求,可以这样做:
- from rest_framework.views import JsonParse
- 给视图类定义一个parser_classes变量,值为列表类型[JsonParser]
- 如果parser_classes = [] ,那就不处理任何数据类型的请求了
序列化组件的使用
from django.db import models
# create your models here.
class Publich(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_lenght=32)
age = models.IntegerField()
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')
通过序列化组件进行接口设计,首先设计url,以GET和POST为例
from django.ruls import re_path
from serializers import views
urlpatterns = [
re_path(r'book/', views.BookView.as_view())
]
新建一个名为app_serializers.py的模块,将所有的序列化的使用集中在这个模块里,对程序 进行解耦:
# -*- coding: utf-8 -*-
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.Serializer):
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
# 当前app中的模块
from .models import Book
# 导入序列化器
from .app_serializer import BookSerializer
class BookView(APIView):
def get(self, request):
origin_books = Book.objects.all()
serialized_books = BookSerializer(origin_books, many=True)
return Response(serialized_books.data)
定义好model和url之后可使用序列化组价的步骤:
导入序列化组件:from rest_framework import serializers
定义序列化类:继承serializerrs.Serializer(建议单独创建一个专用模块来存放所有的序列化类)class BookSerializer(serializers.Serializer):pass
定义需要返回的字段:(字段类型可以与model中的类型不一致,参数也可以调整),字段名称必须与model中的一致。
在GET接口或几种,获取QuerySet
开始序列化:将QuerySet作为第一个参数传给序列化器类,many默认为False,如果返回的数据是一个列表嵌套字典的多个对象那个集合,需要改为many=True
-
返回:将序列化对象的data属性返回即可
rest_framework.response的Response对象,它是DRF重新封装的相应对象。该对象在返回响应数据的时候,会判断客户端类型,如果是浏览器,它会以web页面的形式返回,如果是POSTMAN这一类的工具,就直接返回Json类型数据。
此外,序列化类中的字段名也可以与model中的字段不一致,但是需要使用source参数来告诉组件原来的字段名,一般我们写成一样的就好了。
class BookSerializer(serializers.Serializer): BookTitle = serializers.CharField(max_length=128, source="title") publishDate = serializers.DateTimeField() price = serializers.DecimalField(max_digits=5, decimal_places=2) # source也可以用于ForeignKey字段 publish = serializers.CharField(max_length=32, source="publish.name") authors = serializers.CharField(max_length=32)
那么多对多字段如何处理?如果将source参数定义为"authors.all",那么取出来的结果将是一个QuerySet,这样的数据对前端并不是很友好,所以我们可以使用序列化器嵌套,或者这样:
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_必须与字段名称一致,否则会报错。
# -*- coding: utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response # 当前app中的模块 from .models import Book from .app_serializer import BookSerializer # Create your views here. class BookView(APIView): def get(self, request): origin_books = Book.objects.all() serialized_books = BookSerializer(origin_books, many=True) return Response(serialized_books.data) 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)
POST接口的实现步骤:
url定义:需要为post新增url,根据规范,url定位资源,http请求方式定义用户行为
定义post方法:在视图类中定义post方法
开始序列化:通过我们定义的序列化类,创建一个序列化对象,传入参数data=request.data(application/json)数据
校验数据:通过实例对象的is_valid()方法,对请求数据的合法性进行校验
保存数据:调用save()方法,将数据插入数据库
插入数据到多对多关系表:如果有多对多字段,手动插入数据到多对多关系表
-
返回:将插入的对象返回
因为多对多字关系字段是沃恩自定义的,而且必须这样定义,返回的数据才有意义,而用户插入数据的时候,serrializers.Serializer没有实现create,我们必须手动插入数据,像这样:
# 第二步, 创建一个序列化类,字段类型不一定要跟models的字段一致
class BookSerializer(serializers.Serializer):
# nid = serializers.CharField(max_length=32)
title = serializers.CharField(max_length=128)
price = serializers.DecimalField(max_digits=5, decimal_places=2)
publish = serializers.CharField()
# 外键字段, 显示__str__方法的返回值
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')
# authors = serializers.CharField(max_length=32) # book_obj.authors.all()
# 多对多字段需要自己手动获取数据,SerializerMethodField()
authors_list = serializers.SerializerMethodField()
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
这样就比较复杂,那么我们**如何让序列化类自动插入数据**?如果字段很多,那么写序列化类也会成为一种负担,有没有更加简单的方式呢?
~~~python
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,**ModelSerializer对Serializer进行了扩展,添加了以下功能:**
- **基于model自动创建一些字段**
- **会自动生成一些验证,比如unique_together验证**
- **包含了简单的默认的create()和updata()**
~~~python
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('title', 'price',)
# fields = "__all__"
~~~