Django rest framework(二)-路由器、解析器、渲染器、验证器
本文为学习官方文档时所做笔记,可以看做是官方文档的全文翻译
路由器
-
自定义一个只读API
from rest_framework.routers import Route, DynamicRoute, SimpleRouter class CustomReadOnlyRouter(SimpleRouter): """ A router for read-only APIs, which doesn't use trailing slashes. """ routes = [ Route( url=r'^{prefix}$', mapping={'get': 'list'}, name='{basename}-list', detail=False, initkwargs={'suffix': 'List'} ), Route( url=r'^{prefix}/{lookup}$', mapping={'get': 'retrieve'}, name='{basename}-detail', detail=True, initkwargs={'suffix': 'Detail'} ), DynamicRoute( url=r'^{prefix}/{lookup}/{url_path}$', name='{basename}-{url_name}', detail=True, initkwargs={} ) #一般用于额外动作@action时的route设置 ]视图:
class UserViewSet(viewsets.ReadOnlyModelViewSet): """ A viewset that provides the standard actions """ queryset = User.objects.all() serializer_class = UserSerializer lookup_field = 'username' @action(detail=True) def group_names(self, request, pk=None): """ Returns a list of all the group names that the given user belongs to. """ user = self.get_object() groups = user.groups.all() return Response([group.name for group in groups])路由
router = CustomReadOnlyRouter() router.register('users', UserViewSet) urlpatterns = router.urls
解析器
-
解析器
-
JSONParser -
FormParser:解析HTML表单内容 -
MultiPartParser:解析多部分HTML表单内容,支持文件上传 -
FileParser:解析原始文件上传内容 ,request.file,由于该解析器的media_type匹配任何内容类型,因此FileUploadParser通常应该是API视图上设置的惟一解析器。# views.py class FileUploadView(views.APIView): parser_classes = [FileUploadParser] def put(self, request, filename, format=None): file_obj = request.data['file'] # ... # do some stuff with uploaded file # ... return Response(status=204) # urls.py urlpatterns = [ # ... url(r'^upload/(?P<filename>[^/]+)$', FileUploadView.as_view()) -
第三方包
-
$ pip install djangorestframework-xml #解析XML $ pip install djangorestframework-yaml #解析YAML
-
-
-
设置解析器
@api_view(['GET']) @parser_classes([JSONParser]) #装饰器设置 ----------- REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', ] }#全局设置 ------------ parser_classes = [FileUploadParser] #视图设置 -
文本解析器为例
class PlainTextParser(BaseParser): """ Plain text parser. """ media_type = 'text/plain' def parse(self, stream, media_type=None, parser_context=None): """ Simply return a string representing the body of the request. stream:表示请求主体的流对象。 media_media:请求内容的格式,通常由header决定而非服务器决定 parser_context:可选的。如果提供,此参数将是一个字典,其中包含解析请求内容可能需要的任何附加上下文。 """ return stream.read()
渲染器
-
渲染器
-
JSONRenderer -
TemplateHTMLRenderer:解析为Django标准的模板呈现,不需要Serializer序列化class UserDetail(generics.RetrieveAPIView): """ A view that returns a templated HTML representation of a given user. """ queryset = User.objects.all() renderer_classes = [TemplateHTMLRenderer] def get(self, request, *args, **kwargs): self.object = self.get_object() return Response({'user': self.object}, template_name='user_detail.html')如果要通过一个服务端同时提供标准模板和序列化数据,那么该渲染器必须放在其他所有渲染器的前面
-
StaticHTMLRenderer:返回已经预渲染好的HTML内容@api_view(['GET']) @renderer_classes([StaticHTMLRenderer]) def simple_html_view(request): data = '<html><body><h1>Hello, world</h1></body></html>' return Response(data) -
BrowsableAbleAPIRenderer:将渲染数据到一个可供浏览的HTML页面,该渲染器将确定其他的某个渲染器将获得最高优先级,并使用该优先级在HTML页面中显示API样式响应。-
自定义该渲染器使其以
Json格式渲染而不是以某个最高优先级的渲染器进行渲染class CustomBrowsableAPIRenderer(BrowsableAPIRenderer): def get_default_renderer(self, view): return JSONRenderer()
-
-
AdminRenderer:以后台管理风格返回渲染,注意具有嵌套或列表序列化器的视图,AdminRenderer无法正确的处理它们,因为HTML表单不能良好地地支持它们
-
HTMLFormRender:将序列化器返回的数据呈现为HTML表单格式,但注意:该渲染器的输出不包括封闭的 -
MultiPartRenderer:该渲染器用于呈现HTML复合表单数据 ,它不适合作为响应渲染器,而是通常用于创建测试请求。
-
-
设置
#全局设置 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', #json渲染,第一个为默认 'rest_framework.renderers.BrowsableAPIRenderer', #可浏览API渲染 ] } -------------- #视图设置 class UserCountView(APIView): renderer_classes = [JSONRenderer] -------------- #装饰器设置 @api_view(['GET']) @renderer_classes([JSONRenderer]) -
自定义渲染器
-
重写
BaseRenderer,设置media_type和format属性,重写render(self, data, media_type=None, renderer_context=None)方法,返回一个字节字符串data:Response()实例化中设置的数据。media_type=None:可选的,为可接收数据数据类型,由内容协商阶段决定,通常由请求头中设置的类型决定render_context=None:可选的,为视图提供额外的上下文信息
-
例子:以纯文本和图像为
data数据作为响应内容的渲染器。from django.utils.encoding import smart_unicode from rest_framework import renderers class PlainTextRenderer(renderers.BaseRenderer): media_type = 'text/plain' format = 'txt' charset = 'iso-8859-1' #默认为UTF8编码,若返回的data是二进制则设置该属性为None render_style = 'binary' #这样做还可以确保(可浏览API)不会尝试将二进制内容显示为字符串。 def render(self, data, media_type=None, renderer_context=None): return data.encode(self.charset)class JPEGRenderer(renderers.BaseRenderer): media_type = 'image/jpeg' format = 'jpg' charset = None render_style = 'binary' def render(self, data, media_type=None, renderer_context=None): return data -
根据请求媒体类型决定序列化类:单个视图函数返回不同渲染类型的数据
@api_view(['GET']) @renderer_classes([TemplateHTMLRenderer, JSONRenderer]) def list_users(request): """ A view that can return JSON or HTML representations of the users in the system. """ queryset = Users.objects.filter(active=True) if request.accepted_renderer.format == 'html': # TemplateHTMLRenderer takes a context dict, # and additionally requires a 'template_name'. # It does not require serialization. data = {'users': queryset} return Response(data, template_name='list_users.html') # JSONRenderer requires serialized data as normal. serializer = UserSerializer(instance=queryset) data = serializer.data return Response(data) -
服务一个大类的媒体类型
#渲染器中 media_type = image/* #表示所有图片类型 media_type = */* #表示所有类型 #如果渲染器中没有设置media_type,则必须在响应中明确指出 return Response(data, content_type='image/png') -
第三方包
$ pip install djangorestframework-xml #渲染为XML $ pip install djangorestframework-yaml #渲染为YAML $ pip install djangorestframework-jsonp #渲染为JSONP $ pip install MessagePace #快速、高效的二进制序列化格式 $ pip install drf-renderer-xlsx #XLSX是世界上最流行的二进制电子表格格式 $ pip install djangorestframework-csv #csv格式 $ pip drf-ujson-renderer #可以提供显着更快的JSON渲染 ¥pip djangorestframework-camel-case #为REST框架提供驼峰式JSON呈现器和解析器,允许序列化器使用python风格的下标字段名,但在API中以javascript风格的驼峰大小写字段名公开。 Pandas #Django REST panda提供了一个序列化器和渲染器,支持通过panda DataFrame API进行的额外的数据处理和输出。Django REST panda包括Pandas风格的CSV文件、Excel工作簿(包括.xls和.xlsx)和许多其他格式的呈现器。 $ pip Rest Framework Latex #通过Laulatex输出PDFs
-
验证器
验证器使用
-
DRF中的验证器与
ModelForm中验证器的不同:前者全部在序列化类中进行验证,后者一部分在表单中验证,一部分在模型实例中验证。前者的验证规则有以下好处- 代码解耦,引入了适当的关注点分离,使代码行为更加明显
- 在使用快捷的
ModelSerializer类和使用显式序列化器类之间切换很容易。ModelSerializer使用的任何验证行为都能很方便的重用 - 打印序列化实例的
repr函数将直接显示它应用的所有验证规则,而不会在模型实例上还会有额外的隐藏验证规则,方便开发者直接阅读
模型:
class CustomerReportRecord(models.Model): time_raised = models.DateTimeField(default=timezone.now, editable=False) #在模型上使用unique验证 reference = models.CharField(unique=True, max_length=20) description = models.TextField()序列化:
#ModelSerializer将自动处理验证规则 class CustomerReportSerializer(serializers.ModelSerializer): class Meta: model = CustomerReportRecord打印:
>>> serializer = CustomerReportSerializer() >>> print(repr(serializer)) CustomerReportSerializer(): id = IntegerField(label='ID', read_only=True) time_raised = DateTimeField(read_only=True) reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>]) #打印出了在模型上的验证规则 description = CharField(style={'type': 'textarea'}) -
有时您希望将验证逻辑放在可重用组件中,以便在整个代码库中轻松重用。这可以通过使用验证器函数和验证器类来实现。 并且由于前文这种更显式的验证规则,DRF框架包含了一些在核心
Django中不可用的验证器类。下面将详细介绍这些类。-
UniqueValidator验证器:强制执行unique=True约束queryset:必须参数,在该查询集中强制唯一性。message:验证错误提示信息lookup:查找行为,默认为exact
from rest_framework.validators import UniqueValidator #该序列化器用于序列化字段上 slug = SlugField( max_length=100, validators=[UniqueValidator(queryset=BlogPost.objects.all())] ) -
UniqueTogetherValidator:强制unique_together约束queryset:必须参数,在该查询集中强制唯一性message:验证错误提示信息fields:必须参数,字段名的列表或元组,这些字段构成一个惟一的集合。
from rest_framework.validators import UniqueTogetherValidator class ExampleSerializer(serializers.Serializer): # ... #该验证器用在序列化元类中 class Meta: validators = [ UniqueTogetherValidator( queryset=ToDoItem.objects.all(), fields=['list', 'position'] ) ] -
UniqueForDateValidator、UniqueForMonthValidator、UniqueForYearValidator:分别强制unique_for_date,unique_for_month和unique_for_year约束queryset:必须参数,在该查询集中强制唯一性fields:必须参数,根据给定日期范围对该字段进行唯一性验证date_field:必须参数,用于确定惟一性约束的日期范围message:验证错误提示信息
from rest_framework.validators import UniqueForYearValidator class ExampleSerializer(serializers.Serializer): published = serializers.DateTimeField(required=True)#如果希望日期字段是可写的,惟一值得注意的是应该确保它始终在输入数据中可用,可以通过设置默认参数,也可以通过设置required=True来保证。 #该验证器用在序列化元类中 class Meta: validators = [ UniqueForYearValidator( queryset=BlogPostItem.objects.all(), field='slug', date_field='published' ) ]注意:日期字段有以下三种情况
-
可写的:如果希望日期字段是可写的,惟一值得注意的是应该确保它始终在输入数据中可用,可以通过设置默认参数,也可以通过设置required=True来保证。
published = serializers.DateTimeField(required=True) -
只读的:设置
read_only=True并给与一个默认值published = serializers.DateTimeField(read_only=True, default=timezone.now) -
隐藏的:使用
HiddenField并设置默认值。此字段类型不接受用户输入,但总是将其默认值返回给序列化器中的validated_data。published = serializers.HiddenField(default=timezone.now)
-
高级特性:默认值
有时序列化器不需要用户输入,但依然需要一个值作为验证输入
-
使用
HiddenField并设置默认值。此字段类型不接受用户输入,但总是将其默认值返回给序列化器中的validated_data。 -
使用
read_only=True并同时使用default给与一个默认值,此字段将在序列化器输出表示中使用,但不能由用户直接设置。 -
高级特性:两个可用的默认类
-
CurrentUserDefault:可用于表示当前用户的默认类。使用它必须在实例化序列化器时将request作为上下文字典的一部分提供。owner = serializers.HiddenField( default=serializers.CurrentUserDefault() ) -
createOnlyDefault:在创建操作期间只能用于设置默认参数的默认类 ,在更新期间,该字段被省略#在创建时,creat_at默认直接创建一个当前时间作为值,之后的更新将不能再对此字段进行更新, created_at = serializers.DateTimeField( default=serializers.CreateOnlyDefault(timezone.now) )
-
自定义验证器
-
在一些模棱两可,如嵌套或更复杂的情况下,可能需要显式地处理验证,而不是依赖于
ModelSerializer自动生成的序列化器类,在这种情况下在元类中设置validators = []即可排除掉默认生成的所有的验证器,再用以下三种方式显式的编写验证器逻辑class BillingRecordSerializer(serializers.ModelSerializer): published = serializers.DateTimeField(required=True)# 1.在字段中设置 def validate_date(self,value) #2.2 为某个字段编写验证逻辑. def validate(self, attrs): #2.2 为所有字段编写验证逻辑. class Meta: fields = ['client', 'date', 'amount'] extra_kwargs = {'client': {'required': False}} #3.使用extra_kwargs对字段添加参数 validators = [] # 移除已存在所有验证器限制 -
自定义验证器的编写已经在序列化器章节有了更详细的介绍

浙公网安备 33010602011771号