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 = [] # 移除已存在所有驗證器限制
-
自定義驗證器的編寫已經在序列化器章節有了更詳細的介紹