斑馬斑馬-23-Django REST Framework (DRF)系列教程
學習和使用一個技術、官方文件至關重要。
一、認證Authentication
Auth needs to be pluggable.— Jacob Kaplan-Moss,一言以蔽之:認證需要可插拔 1、How authentication is determined(如何確定身份驗證) 常見的認證方式A:BasicAuthentication This authentication scheme uses HTTP Basic Authentication, signed against a user's username and password. Basic authentication is generally only appropriate for testing. Note: If you use BasicAuthentication in production you must ensure that your API is only available over https. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.
B:SessionAuthentication This authentication scheme uses Django's default session backend for authentication. Session authentication is appropriate for AJAX clients that are running in the same session context as your website. If successfully authenticated, SessionAuthentication provides the following credentials. * request.user will be a Django User instance. * request.auth will be None. Warning: Always use Django's standard login view when creating login pages. This will ensure your login views are properly protected. CSRF validation in REST framework works slightly differently to standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied.
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ]}
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status # GenericAPIView 進一步封裝,把呼叫的類封裝出來 class BookAPIView(APIView): ''' 查詢所有圖書,增加圖書 ''' authentication_classes = (SessionAuthentication, BasicAuthentication) permission_classes = (IsAuthenticated,) def get(self, request, format=None): """ 查詢所有圖書 路由:GET /books/info?page=1&page_size=5 """ book_list = BookInfo.objects.all() # 2:建立可以序列化列表的序列化器 serializer_list = BookInfoSerializer(instance=book_list, many=True) # 3:轉換資料 # return JsonResponse(serializer_list.data, safe=False) return Response(serializer_list.data, status=status.HTTP_200_OK)views中進行檢視設定
二、許可權Permissions
Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization. 身份驗證或身份識別本身通常不足以獲取資訊或程式碼的訪問許可權。因此,請求訪問的實體必須具有授權。1、How permissions are determined(如何確定許可權)
常見的許可權型別AllowAny(所有使用者) AllowAny許可權類將允許不受限制的訪問,而不管該請求是否已通過身份驗證或未經身份驗證。 IsAuthenticated(註冊使用者) IsAuthenticated 許可權類將拒絕任何未經身份驗證的使用者的許可權,並允許其他許可權。 如果你希望你的API僅供註冊使用者訪問,則此許可權適用。 如果你希望你的API允許匿名使用者讀取許可權,並且只允許對已通過身份驗證的使用者進行寫入許可權,則此許可權是適合的。 IsAdminUser(管理員使用者) 除非user.is_staff為True,否則IsAdminUser許可權類將拒絕任何使用者的許可權,在這種情況下將允許許可權。 如果你希望你的API只能被部分受信任的管理員訪問,則此許可權是適合的。 IsAuthenticatedOrReadOnly IsAuthenticatedOrReadOnly 將允許經過身份驗證的使用者執行任何請求。只有當請求方法是“安全”方法(GET, HEAD 或 OPTIONS)之一時,才允許未經授權的使用者請求。 如果你希望你的API允許匿名使用者讀取許可權,並且只允許對已通過身份驗證的使用者進行寫入許可權,則此許可權是適合的。
1:Setting thepermissionpolicy設定許可權方案(setting檔案進行全域性)
'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', )
2:Setting thepermissionpolicy設定許可權方案(區域性全域性:views.py)
permission_classes = (IsAuthenticated,) #區域性許可權
3:測試,管理員登入
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.viewsets import ModelViewSet from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated, AllowAny,IsAdminUser # GenericAPIView 進一步封裝,把呼叫的類封裝出來 class BookAPIView(ModelViewSet): ''' 查詢所有圖書,增加圖書 ''' # 1:區域性認證 authentication_classes = [SessionAuthentication] # 2:區域性許可權 permission_classes = [IsAdminUser] queryset = BookInfo.objects.all() serializer_class = BookInfoSerializerView15.py
2:建立管理員
python manage.py createsuperuser
使用者名稱:admin 密碼:1
3:通過django中admin使用者登入,
4:檢視
三、限流Throttling
Twitter API rate limiting response,一言以蔽之:限制響應次數1、How throttling is determined(如何確定限流)
As with permissions and authentication, throttling in REST framework is always defined as a list of classes.
Before running the main body of the view each throttle in the list is checked. If any throttle check fails an exceptions.
Throttled exception will be raised, and the main body of the view will not run.
常見的限流型別
AnonRateThrottle The AnonRateThrottle will only ever throttle unauthenticated users. The IP address of the incoming request is used to generate a unique key to throttle against. The allowed request rate is determined from one of the following (in order of preference). The rate property on the class, which may be provided by overriding AnonRateThrottle and setting the property. The DEFAULT_THROTTLE_RATES['anon'] setting. AnonRateThrottle is suitable if you want to restrict the rate of requests from unknown sources.
限制匿名使用者
UserRateThrottle The UserRateThrottle will throttle users to a given rate of requests across the API. The user id is used to generate a unique key to throttle against. Unauthenticated requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against. The allowed request rate is determined from one of the following (in order of preference). The rate property on the class, which may be provided by overriding UserRateThrottle and setting the property. The DEFAULT_THROTTLE_RATES['user'] setting.
限流方案
1:Setting the throttle policy設定限流方案(setting檔案進行全域性)
'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ], 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', 'user': '1000/day' }
2:Setting the throttle policy設定區域性限流方案(views檔案進行)
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.viewsets import ModelViewSet from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser from rest_framework.throttling import AnonRateThrottle,UserRateThrottle # GenericAPIView 進一步封裝,把呼叫的類封裝出來 class BookAPIView(ModelViewSet): ''' 查詢所有圖書,增加圖書 ''' # 1:區域性認證 authentication_classes = [SessionAuthentication] # 2:區域性許可權 permission_classes = [IsAdminUser] # 3:區域性限流 throttle_classes = [UserRateThrottle] queryset = BookInfo.objects.all() serializer_class = BookInfoSerializerview15.py
3:測試
四、分頁Pagination
Django provides a few classes that help you manage paginated data – that is, data that’s split across several pages, with “Previous/Next” links.
Django提供了上一頁/下一頁的方式來進行分頁
1、Howpagination is determined(如何確定分頁)
1:Setting the pagination policy設定分頁方案(setting檔案進行全域性)
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
}
2:Setting the paginationpolicy設定區域性限流方案(views檔案進行)
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.viewsets import ModelViewSet from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser from rest_framework.throttling import AnonRateThrottle, UserRateThrottle from rest_framework.pagination import LimitOffsetPagination,PageNumberPagination # GenericAPIView 進一步封裝,把呼叫的類封裝出來 class BookAPIView(ModelViewSet): ''' 查詢所有圖書,增加圖書 ''' queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer # 1:區域性分頁 pagination_class = PageNumberPaginationviews.py
2、自定義分頁
PageNumberPagination中存在一個問題,即:page_size 無法修改,我們可以通過自定義類來實現
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.viewsets import ModelViewSet from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser from rest_framework.throttling import AnonRateThrottle, UserRateThrottle from rest_framework.pagination import LimitOffsetPagination,PageNumberPagination # GenericAPIView 進一步封裝,把呼叫的類封裝出來 # 自定義分頁物件 class MyPageNumberPagination(PageNumberPagination): page_size_query_param = "page_size" max_page_size = 5 #最大不能超過5 class BookAPIView(ModelViewSet): ''' 查詢所有圖書,增加圖書 ''' queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer # 1:自定義分頁 pagination_class = MyPageNumberPaginationview16.py
五、過濾
The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects.從資料庫表中選擇一些子集。
一、步驟
1:下載 pip install django-filter
2:配置setting
INSTALLED_APPS = [ ...... 'django_filters', ] REST_FRAMEWORK = { ...... 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] }settings.py
2:檢視設定
pip install django-filter You should now either add the filter backend to your settings: REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] } Or add the filter backend to an individual View or ViewSet. from django_filters.rest_framework import DjangoFilterBackend class UserListView(generics.ListAPIView): ... filter_backends = [DjangoFilterBackend] If all you need is simple equality-based filtering, you can set a filterset_fields attribute on the view, or viewset, listing the set of fields you wish to filter against. class ProductList(generics.ListAPIView): queryset = Product.objects.all() serializer_class = ProductSerializer filter_backends = [DjangoFilterBackend] filterset_fields = ['category', 'in_stock'] This will automatically create a FilterSet class for the given fields, and will allow you to make requests such as: http://example.com/api/products?category=clothing&in_stock=True官方文件
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.viewsets import ModelViewSet from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination from django_filters.rest_framework import DjangoFilterBackend # GenericAPIView 進一步封裝,把呼叫的類封裝出來 # 自定義分頁物件 class MyPageNumberPagination(PageNumberPagination): page_size_query_param = "page_size" max_page_size = 5 # 最大不能超過5 class BookAPIView(ModelViewSet): ''' 查詢所有圖書,增加圖書 ''' queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer # 1:自定義分頁 pagination_class = MyPageNumberPagination # 2:區域性過濾 filter_backends = [DjangoFilterBackend] filterset_fields = ['id','btitle']
測試效果
六、排序OrderingFilter
from APP01.models import BookInfo, HeroInfo from APP01.serializer import BookInfoSerializer, HeroInfoSerializer from rest_framework.viewsets import ModelViewSet from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination from rest_framework.filters import OrderingFilter from django_filters.rest_framework import DjangoFilterBackend # GenericAPIView 進一步封裝,把呼叫的類封裝出來 # 自定義分頁物件 class MyPageNumberPagination(PageNumberPagination): page_size = 5 page_size_query_param = "page_size" max_page_size = 5 # 最大不能超過5 class BookAPIView(ModelViewSet): ''' 查詢所有圖書,增加圖書 ''' queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer # 1:自定義分頁 pagination_class = MyPageNumberPagination # 2:區域性過濾 filter_backends = [DjangoFilterBackend] filterset_fields = ['id','btitle'] # 3:排序 filter_backends = [OrderingFilter] ordering_fields = ['id', 'btitle','bread']view17.py
注意:
1:排序所使用的包:from rest_framework.filters import OrderingFilter
2:正序:?ordering=username
3:倒序:?
ordering=-username
4:多欄位排序:?ordering=account,username
七、異常處理Exceptions
Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure.— Doug Hellmann,
一、常見的異常型別
APIException:介面異常
Signature: APIException()
The base class for all exceptions raised inside an APIView class or @api_view.
AuthenticationFailed:驗證失敗
Signature: AuthenticationFailed(detail=None, code=None)
Raised when an incoming request includes incorrect authentication.
By default this exception results in a response with the HTTP status code "401 Unauthenticated", but it may also result in a "403 Forbidden" response, depending on the authentication scheme in use. See the authentication documentation for more details.
NotAuthenticated:未認證
Signature: NotAuthenticated(detail=None, code=None)
Raised when an unauthenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code "401 Unauthenticated", but it may also result in a "403 Forbidden" response, depending on the authentication scheme in use. See the authentication documentation for more details.
PermissionDenied:沒有許可權
Signature: PermissionDenied(detail=None, code=None)
Raised when an authenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code "403 Forbidden".
NotFound:未找到
Signature: NotFound(detail=None, code=None)
Raised when a resource does not exists at the given URL. This exception is equivalent to the standard Http404 Django exception.
By default this exception results in a response with the HTTP status code "404 Not Found".
MethodNotAllowed:方法未允許
Signature: MethodNotAllowed(method, detail=None, code=None)
Raised when an incoming request occurs that does not map to a handler method on the view.
By default this exception results in a response with the HTTP status code "405 Method Not Allowed".
NotAcceptable:不能接受的
Signature: NotAcceptable(detail=None, code=None)
Raised when an incoming request occurs with an Accept header that cannot be satisfied by any of the available renderers.
By default this exception results in a response with the HTTP status code "406 Not Acceptable".
UnsupportedMediaType:不支援的媒體型別
Signature: UnsupportedMediaType(media_type, detail=None, code=None)
Raised if there are no parsers that can handle the content type of the request data when accessing request.data.
By default this exception results in a response with the HTTP status code "415 Unsupported Media Type".
Throttled:節流
Signature: Throttled(wait=None, detail=None, code=None)
Raised when an incoming request fails the throttling checks.
By default this exception results in a response with the HTTP status code "429 Too Many Requests".
ValidationError:驗證錯誤
Signature: ValidationError(detail, code=None)
The ValidationError exception is slightly different from the other APIException classes:
二、自定義異常
1:Setting thepermissionpolicy設定許可權方案(setting檔案進行全域性)
'DEFAULT_PERMISSION_CLASSES': (
'EXCEPTION_HANDLER': 'APP01.my_exception.custom_exception_handler'
)
2:建立一個自定義異常類
'''自定義異常處理類''' from rest_framework.views import exception_handler from rest_framework.response import Response def custom_exception_handler(exc, context): # Call REST framework's default exception handler first, # to get the standard error response. response = exception_handler(exc, context) # Now add the HTTP status code to the response. if response is not None: response.data['status_code'] = response.status_code return Response("漂亮的錯誤頁面")custom_exception_handler