它是基於Django的,幫助我們快速開發符合RESTful規範的介面框架。 一 路由 可以通過路由as_view()傳參 根據請求方式的不同執行對應不同的方法 在routers模塊下 封裝了很多關於路由的方法 , 最基礎的BaseRouter類,給我提供自定製的介面。 下麵這個方法給我們提供了自動生 ...
它是基於Django的,幫助我們快速開發符合RESTful規範的介面框架。
一 路由
可以通過路由as_view()傳參 根據請求方式的不同執行對應不同的方法
在routers模塊下 封裝了很多關於路由的方法 , 最基礎的BaseRouter類,給我提供自定製的介面。
下麵這個方法給我們提供了自動生成兩條帶參數的url
from rest_framework import routers from django.conf.urls import url, include from course.models import Course from course.views import CourseView routers = routers.DefaultRouter() routers.register('Course', CourseView) urlpatterns = [ url(r'^', include(routers.urls)), ]
二 視圖
幫助開發者提供了一些類,併在類中提供了多種方法供我們使用,下圖是提供的主要的類以及繼承關係。
提供其他一些視圖函數類,可以去源碼里看。
三 版本控制
下麵以URL上控製版本為例
1、添加配置
REST_FRAMEWORK = { # 預設使用的版本控制類 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', # 允許的版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 版本使用的參數名稱 'VERSION_PARAM': 'version', # 預設使用的版本 'DEFAULT_VERSION': 'v1', }
2、設置路由
urlpatterns = [ #url(r'^admin/', admin.site.urls), url(r'^api/(?P<version>\w+)/', include('api.urls')), ]
3、獲取版本
request.version
四 認證
rest_framework給我們提供了認證的介面,由BaseAuthentication類提供介面,也有一些封裝好的認證類(請走入源碼....)
介面函數 authticate 認證成功返回一元組(user,token)分別賦值給request.user 和 request.auth
下麵是一個簡單的認證示例
class Auth(BaseAuthentication): def authenticate(self, request): token = request.query_params.get('token') obj = models.Token.objects.filter(token=token).first() if not obj: raise AuthenticationFailed({'code': 1001, 'error': '認證失敗'}) return (obj.user.username, obj)
我們的認證類可以放在局部視圖函數,也可以配置為全局認證。
# 局部視圖函數認證 class MyView(APIView): authentication_classes = [Auth] pass
# 全局配置 在settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [Auth], }
五 許可權
由BasePermission類給我提供介面 介面函數為 has_permission 以及 has_object_permission
有許可權返回True 沒有則返回False,預設的許可權類為下圖。
# 允許任何人訪問 class AllowAny(BasePermission): """ Allow any access. This isn't strictly required, since you could use an empty permission_classes list, but it's useful because it makes the intention more explicit. """ def has_permission(self, request, view): return True
介面類為下圖
class BasePermission(object): """ A base class from which all permission classes should inherit. """ def has_permission(self, request, view): """ Return `True` if permission is granted, `False` otherwise. """ # 這裡寫我們的許可權邏輯 return True def has_object_permission(self, request, view, obj): """ Return `True` if permission is granted, `False` otherwise. """ return True
還封裝了一些許可權類,只允許admin用戶訪問的許可權,只給認證的用戶許可權等等,請走源碼........
六 頻率
基礎的BaseThrottle類提供介面 介面函數為 allow_request,如果返回False則走wait
SimpleRateThrottle類給我們提供了get_cache_key介面,繼承這個類要寫rate(num_request, duration)多長時間內訪問次數
實現原理如下代碼:
class SimpleRateThrottle(BaseThrottle): def allow_request(self, request, view): if self.rate is None: return True self.key = self.get_cache_key(request, view) if self.key is None: return True self.history = self.cache.get(self.key, []) self.now = self.timer() # 原理的實現邏輯 while self.history and self.history[-1] <= self.now -self.duration: self.history.pop() if len(self.history) >= self.num_requests: return self.throttle_failure() return self.throttle_success()
這裡就放這些~~具體~請大家走入源碼.......
七 序列化
對queryset序列化以及對請求數據格式驗證。
通常繼承兩個類 Serializer 以及 ModelSerializer
Serializer 序列化的每個欄位都要自己寫 ModelSerializer 會根據資料庫表渲染所有欄位
註意sourse 以及 鉤子函數的應用 代碼如下:
class CourseDetailModelSerializers(serializers.ModelSerializer): title = serializers.CharField(source='course.name') img = serializers.ImageField(source='course.course_img') level = serializers.CharField(source='course.get_level_display') recommends = serializers.SerializerMethodField() chapters = serializers.SerializerMethodField() def get_recommends(self, obj): queryset = obj.recommend_courses.all() return [{'id': row.id, 'title': row.name} for row in queryset] def get_chapters(self, obj): queryset = obj.course.course_chapters.all() return [{'id': row.id, 'name': row.name} for row in queryset] class Meta: model = CourseDetail fields = ['course', 'title', 'img', 'level', 'why_study', 'chapters', 'recommends']
八 分頁
對從資料庫中獲取到的數據進行分頁處理 SQL --> limit offset
- 根據頁碼:http://www.myclass.com/api/v1/student/?page=1&size=10
- 根據索引:http://www.myclass.com/api/v1/student/?offset=60&limit=10
- 根據游標:http://www.myclass.com/api/v1/student/?page=erd8
頁碼越大速度越慢,為什麼怎麼解決?
- 原因:頁碼越大向後需要掃描的行數越多,因為每次都是從0開始掃描
- 解決:
- 限制當前顯示的頁數
- 記錄當前頁面數據ID的最大值和最小值,再次分頁時,根據ID進行篩選,在分頁
rest_framework 分頁的配置
- 全局分頁配置
# settings.py REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 100 }
- 修改分頁風格
class MyPagination(PageNumberPagination): page_size = 100 page_size_query_param = 'page_size' max_page_size = 1000 # 然後在視圖中使用.pagination_class屬性調用該自定義類 class MyView(generics.ListAPIView): queryset = Billing.objects.all() serializer_class = BillingRecordsSerializer pagination_class = MyPagination # 或者是在settings.py中修改DEFAULT_PAGINATION_CLASS REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.MyPagination' }
rest_framework給我提供的API
1、 PageNumberPagination
?1 |
GET https: / / api.example.org / accounts / ?page = 4
|
響應對象
HTTP 200 OK { "count": 1023 "next": "https://api.example.org/accounts/?page=5", "previous": "https://api.example.org/accounts/?page=3", "results": [ … ] }
配置屬性
- page_size 每頁顯示對象的數量 如果設置了就重寫PAGE_SIZE
- page_query_param 頁面查詢參數 指示分頁空間的查詢參數的名字
- page_size_query_param 允許客戶端根據每個請求設置頁面大小 一般都為None
- max_page_size 設置了page_size_query_param 才有意義 客戶端請求頁面中顯示最大數量
- last_page_strings 儲存page_query_param參數請求過的值列表或元組
2、LImitOffsetPagination
路由配置以及返回類型
GET https://api.example.org/accounts/?limit=100&offset=400 HTTP 200 OK { "count": 1023 "next": "https://api.example.org/accounts/?limit=100&offset=500", "previous": "https://api.example.org/accounts/?limit=100&offset=300", "results": [ … ] }
配置參數
- page_size 每頁顯示對象的數量 如果設置了就重寫PAGE_SIZE
- default_limit: 如果客戶端沒有提供,則預設使用與PAGE_SIZE值一樣。
- limit_query_param:表示限制查詢參數的名字,預設為’limit’
- offset_query_param:表示偏移參數的名字, 預設為’offset’
- max_limit:允許頁面中顯示的最大數量,預設為None
3、CursorPagination
- 基於游標的分頁顯示了一個不透明的“cursor”指示器,客戶端可以使用它來瀏覽結果集。
- 這種分頁方式只允許用戶向前或向後進行查詢。並且不允許客戶端導航到任意位置。
- 基於游標的分頁方式比較複雜,它要求結果集給出一個固定的順序,並且不允許客戶端任意的對結果集進行索引
全局配置如下
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination', 'PAGE_SIZE': 100 }
配置參數:
- page_size:顯示的最大條數
- cursor_query_param: 游標查詢參數名,預設為’cursor’
- ordering: 排序欄位名的列表或者元組,例如ordering = ‘slug’,預設為-created
4、自定義分頁
- 繼承pagination.BasePagination
- 重寫paginate_queryset(self, queryset, request, view=None)方法 ,
初始化queryset對象,設置pagination實例 返回一個包含用戶請求內容的可迭代對象 形成分頁對象
- 重寫get_paginated_response(self, data)方法
序列化請求頁中所包含的對象,返回一個Response對象
class CustomPagination(pagination.PageNumberPagination): def get_paginated_response(self, data): return Response({ 'links': { 'next': self.get_next_link(), 'previous': self.get_previous_link() }, 'count': self.page.paginator.count, 'results': data }) # 設置自定義分頁、 REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination', 'PAGE_SIZE': 100 }
九 解析器
預設的三個解析器
- JsonParser Json數據解析器
- FormParser 和 MultiPartParser 一般同時使用
Both request.data
will be populated with a QueryDict
. 官方文檔的解釋
DEFAULTS = { # rest_framework settings.py 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ), }
十 渲染器
預設的兩個渲染器,一個是Json的,一個是用瀏覽器訪問rest_framework自帶的模板的
DEFAULTS = { # rest_framework setting.py 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ), }