REST framework是什么?
Django REST框架是一个功能强大且灵活的工具包,用于构建Web API
REST framework的优点 :
1,Web可浏览API为开发人员带来了巨大的可用性。(The Web browsable API is a huge usability win for your developers.)
2,身份验证策略包括OAuth1a和OAuth2的程序包;
3,支持ORM和非ORM数据源的序列化;
4,可自定义;
5,丰富的文档和良好的社区支持;
6,受到国际知名公司的使用和信任,包括Mozilla,Red Hat,Heroku和Eventbrite。
在Django项目中使用:
1,在Django项目settings.py的INSTALLED_APPS中注册rest_framework 应用
2,每个视图类继承自 from rest_framework.views import APIView
下载:(使用清华源)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple djangorestframework
1,请求
REST framework 的 Request 类扩展自标准的 HttpRequest,并做了相应的增强,比如更加灵活的请求解析和认证
#使用组合的方式扩展了HttpRequest类
class Request(object):
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request
#在REST framework中初始化request对象
class APIView(View):
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
request.data :返回请求主体的解析内容,包括所有解析的内容,文件(file) 和 非文件(non-file inputs);不仅仅支持表单数据,还支持JSON数据;支持解析 POST 以外的 HTTP method ,比如 PUT,PATCH
request.query_params :等同于 request.GET;为了代码更加清晰可读,推荐使用 request.query_params
request.parsers :当前使用的解析器列表
request.user:通常会返回 django.contrib.auth.models.User 的一个实例,但其行为取决于正在使用的身份验证策略;若请求未经身份验证,则返回 django.contrib.auth.models.AnonymousUser 的实例
request.auth:返回任何附加的认证上下文(authentication context),通常可能是请求经过身份验证的令牌(token)实例
request.authenticators:当前使用的认证器(authenticator)列表
2,响应
REST framework 的 Response 类是 Django 的 SimpleTemplateResponse 的子类
构造方法: Response(data, status=None, template_name=None, headers=None, content_type=None)
data: 响应的序列化数据。
status: 响应的状态代码。默认为200。
template_name: 选择 HTMLRenderer 时使用的模板名称。
headers: 设置 HTTP header,字典类型。
content_type: 响应的内容类型,通常渲染器会根据内容协商的结果自动设置,但有些时候需要手动指定。
class Response(SimpleTemplateResponse):
@property
def rendered_content(self):
#使用渲染器渲染序列化后的数据
renderer = getattr(self, 'accepted_renderer', None)
ret = renderer.render(self.data, accepted_media_type, context)
REST framework 提供了一个 APIView 类,它继承于 Django 的 View 类。
1,View与APIView源码分析
View:
#views.py
from django.views import View
class BookView(View):
pass
#-----------------------------
#urls.py
url(r'^books/$', views.BookView.as_view()) #项目启动时找到类方法as_view并执行
#View部分源码
class View(object):
@classonlymethod
def as_view(cls, **initkwargs): #在视图类BookView的父类View中找到类方法as_view,执行它返回一个view函数
def view(request, *args, **kwargs): # 当对应url中的路径匹配成功时,调用执行此view函数
self = cls(**initkwargs)
return self.dispatch(request, *args, **kwargs)
return view
#分发方法
def dispatch(self, request, *args, **kwargs):
#http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) #在这里调用我们在视图类中的定义的get,post等函数,并返回响应
APIView:
#views.py
from rest_framework.views import APIView
class BookView(APIView):
pass
#------------------------------------------------
#urls.py
url(r'^books/$', views.BookView.as_view()) #项目启动时找到类方法as_view并执行
#APIView部分源码
class APIView(View):
@classmethod
def as_view(cls, **initkwargs): #项目启动时最先在这找到类方法as_view,执行它返回view函数
view = super(APIView, cls).as_view(**initkwargs) # 此view函数继承自其父类View
return csrf_exempt(view)
#执行view函数时,self.dispatch(request, *args, **kwargs) 调用dispatch方法,
#先从对象的类中找,再去其父类APIView中找,在这能找到dispatch方法,所以最终调用的
#是APIView类中的dispatch方法,而不再是View类中的dispatch方法!
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
initialize_request(self, request, *args, **kwargs):
确保传递给处理方法的请求对象是 Request 的一个实例,而不是通常的 Django HttpRequest。
initial(self, request, *args, **kwargs):
用于执行处理方法被调用之前需要的任何操作。此方法用于强制执行权限和限流,并执行内容协商。
使用APIView 5种接口的实现:
url(r'^books/$', views.BookView.as_view()),
url(r'^books/(\d+)/$', views.BookDetailView.as_view()),
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
serializer = BookSerializer(book_list, many=True)
return Response(serializer.data)
def post(self, request):
serializer = BookSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
class BookDetailView(APIView):
def get(self, request, pk):
book_obj = Book.objects.filter(pk=pk).first()
serializer = BookSerializer(book_obj, many=False)
return Response(serializer.data)
def put(self, request, pk):
book_obj = Book.objects.filter(pk=pk).first()
serializer = BookSerializer(data=request.data, instance=book_obj)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response("ok")
2,GenericAPIView / mixin类
2.1 GenericAPIView 类继承于 REST framework 的 APIView 类,为标准列表和详细视图添加了常见的行为。
get_queryset(self) -->默认返回由 queryset 属性指定的查询集;
应该始终使用此方法, 而不是直接访问 self.queryset,因为 REST 会在内部对 self.queryset 的结果进行缓存用于后续所有请求。
get_serializer_class(self) -->返回用于序列化的类。默认返回 serializer_class 属性
2.2 mixin 类用于提供基本视图行为的操作
ListModelMixin -->提供一个 list(request, *args, **kwargs) 方法,实现了列出一个查询集;响应数据可以设置分页。
CreateModelMixin -->提供 create(request, *args, **kwargs) 方法,实现创建和保存新模型实例
RetrieveModelMixin -->提供 retrieve(request, *args, **kwargs) 方法,该方法实现在响应中返回现有的模型实例
UpdateModelMixin -->提供 update(request, *args, **kwargs) 方法,实现更新和保存现有模型实例。
还提供了一个 partial_update(request, *args, **kwargs) 方法,它与更新方法类似,只是更新的所有字段都是可选的。这允许支持 HTTP PATCH 请求。
DestroyModelMixin -->提供一个 destroy(request, *args, **kwargs) 方法,实现现有模型实例的删除
使用GenericAPIView与mixin 类 5种接口的实现:
url(r'^books/$', views.BookView.as_view()),
url(r'^books/(?P\d+)/$', views.BookDetailView.as_view()),
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
from rest_framework.generics import GenericAPIView
class BookView(CreateModelMixin,ListModelMixin,GenericAPIView):
queryset=Book.objects.all()
serializer_class=BookSerializers
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class BookDetailView(DestroyModelMixin,UpdateModelMixin,RetrieveModelMixin,GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
def get(self,request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self,request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self,request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
2.3 内置通用视图类
class CreateAPIView(CreateModelMixin,GenericAPIView) -->仅用于创建实例;提供一个 post 请求的处理方法
class ListAPIView(ListModelMixin,GenericAPIView) -->仅用于读取模型实例列表。提供一个 get 请求的处理方法
class RetrieveAPIView(RetrieveModelMixin,GenericAPIView) -->仅用于查询单个模型实例。提供一个 get 请求的处理方法
class DestroyAPIView(DestroyModelMixin,GenericAPIView) -->仅用于删除单个模型实例;提供一个 delete 请求的处理方法
class UpdateAPIView(UpdateModelMixin,GenericAPIView) -->仅用于更新单个模型实例。提供 put 和 patch 请求的处理方法
ListCreateAPIView -->既可以获取实例集合,也可以创建实例列表;提供 get 和 post 请求的处理方法
RetrieveUpdateDestroyAPIView -->同时支持查询,更新,删除;提供 get,put,patch 和 delete 请求的处理方法
使用内置通用视图 5种接口的实现:
url(r'^books/$', views.BookView.as_view()),
url(r'^books/(?P\d+)/$', views.BookDetailView.as_view()),
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
class BookView(ListCreateAPIView):
queryset=Book.objects.all
serializer_class=BookSerializers
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all
serializer_class = BookSerializers
3, 视图集 ViewSet
Django REST framework 允许将一组相关视图的逻辑组合到一个称为 ViewSet 的类中。
ModelViewSet 类继承自 GenericAPIView,并通过混合各种 mixin 类的行为来包含各种操作的实现。
使用ModelViewSet 类 5种接口的实现:
url(r'^books/$', views.BookModelView.as_view({'get':'list','post':'create'})),
url(r'^books/(?P\d+)/$', views.BookModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
from rest_framework.viewsets import ModelViewSet
class BookModelView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
4,各种视图类的继承关系图
序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python 数据类型,然后可以将它们轻松地呈现(渲染)为 JSON,XML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。
REST framework 提供了一个 Serializer 类,它提供了一种强大的通用方法来控制响应的输出,以及一个 ModelSerializer 类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式。
1,声明序列化类
声明一个序列化类,使用它来序列化和反序列化与对象相对应的数据;声明一个序列化类看起来非常类似于声明一个表单
好的做法是将所有的序列化类写在一个 serializers.py文件中。
from .models import Book
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title = serializers.CharField()
# publishDate = serializers.DateField()
price = serializers.CharField()
# 多对一字段
publish_name = serializers.CharField(source='publish.name')
# publish_city = serializers.CharField(source='publish.city')
# 多对多字段
authors = serializers.SerializerMethodField()
# 默认方法名为get_
def get_authors(self,obj):
data = []
for author_obj in obj.authors.all():
author_data = {}
author_data['name']=author_obj.name
author_data['age']=author_obj.age
data.append(author_data)
return data
ModelSerializer 类提供了一个快捷方式,可让你自动创建一个 Serializer 类,其中的字段与模型类字段对应
ModelSerializer 类与常规 Serializer 类不同之处在于:
①它会根据模型自动生成一组字段。
②它会自动为序列化类生成验证器,例如 unique_together 验证器。
③它包含 .create() 和 .update() 的简单默认实现
从版本 3.3.0 开始,必须提供其中一个属性 fields 或 exclude。
任何关系(如模型上的外键)都将映射到 PrimaryKeyRelatedField。
ModelSerializer 对关系字段的默认表示是使用相关实例的主键。
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
# fields = ('title','price')
# exclude = ('id', 'publishDate')
class BookSerializer(serializers.ModelSerializer):
# 一对多和多对多字段默认取其id值,若想提供其他值,需要自定义;其他简单字段也可以显示指定字段以覆盖默认字段
# title = serializers.CharField()
publish = serializers.CharField(source='publish.name')
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
data = []
for author_obj in obj.authors.all():
author_data = {}
author_data['name'] = author_obj.name
author_data['age'] = author_obj.age
data.append(author_data)
return data
class Meta:
model = Book
fields = '__all__'
查看ModelSerializer自动创建的Serializer 类的字段信息:
>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
HyperlinkedModelSerializer 类与 ModelSerializer 类相似,只不过它使用超链接来表示关系而不是主键。
默认情况下,序列化器将包含一个 url 字段而不是主键字段。
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Account
fields = ('url', 'id', 'account_name', 'users', 'created')
2,BaseSerializer API
Serializer 类继承自BaseSerializer,ModelSerializer 类继承自Serializer 类。
BaseSerializer 类可以用来方便地支持其他序列化和反序列化风格。
.data - 返回传出的原始表示。
.is_valid() - 反序列化并验证传入的数据。
.validated_data - 返回验证的传入数据。
.errors - 在验证期间返回错误。
.save() - 将验证的数据保存到对象实例中。
有四种方法可以被覆盖,这取决于你希望序列化类支持的功能:
.to_representation() - 重写此操作以支持序列化,用于读取操作。
.to_internal_value() - 重写此操作以支持反序列化,以用于写入操作。
.create() 和 .update() - 覆盖其中一个或两个以支持保存实例。
3,序列化对象与反序列化对象
将模型实例转换为 Python 原生数据类型
serializer = CommentSerializer(comment)
serializer.data
序列化多个对象
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
反序列化对象:
将原生数据类型恢复成通过验证的数据字典
serializer = CommentSerializer(data=request.data)
serializer.is_valid()
# True;通过验证的数据字典
serializer.validated_data
# False;包含一个代表错误消息的字典
serializer.errors
4,保存实例
需要实现 .create() 和 .update() 方法
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
调用 .save() 将创建一个新实例或更新现有实例,具体取决于在实例化序列化类时是否传递了现有实例
#save方法的源码
class BaseSerializer(Field):
def save(self, **kwargs):
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.instance
在保存实例的时候注入额外的数据。这些附加数据可能包含当前用户,当前时间或其他任何不属于请求数据的信息。
调用 .create() 或 .update() 时,任何其他关键字参数都将包含在 validated_data 参数中
serializer.save(owner=request.user)
5,字段验证
validate_
只有一个参数,就是需要验证的字段值;应返回验证值或引发 serializers.ValidationError
def validate_title(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("Blog post is not about Django")
return value
如果要对多个字段进行其他的验证,请将一个名为 validate() 的方法添加到Serializer 子类中。
只有一个参数,它是一个字段值(field-value)的字典;应返回验证值或引发 serializers.ValidationError
def validate(self, data):
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return data
序列化器上的各个字段可以包含验证器,方法是在字段实例上声明它们:
def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('Not a multiple of ten')
class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])
6,其他补充
部分更新:
默认情况下,序列化程序必须为所有必填字段传递值,否则会引发验证错误。可以使用 partial 参数以允许部分更新。
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
嵌套对象:
Serializer 类本身就是一种 Field,可以用来表示一个对象类型嵌套在另一个对象类型中的关系;
如果嵌套对象可以是 None 值,则应将 required = False 标志传递给嵌套的序列化类;
同样,如果嵌套对象是一个列表,则应将 many = True 标志传递给嵌套的序列化类。
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
自定义多个对象的创建:
class BookListSerializer(serializers.ListSerializer):
def create(self, validated_data):
books = [Book(**item) for item in validated_data]
return Book.objects.bulk_create(books)
class BookSerializer(serializers.Serializer):
...
class Meta:
list_serializer_class = BookListSerializer
自定义多个对象的更新 -->见官方文档