先建立一個django項目,在項目中建立一些表,用來測試rest framework的各類組件數據庫
models.pydjango
class UserInfo(models.Model): """用戶信息表""" user = models.CharField(max_length=32) pwd = models.CharField(max_length=32) class UserToken(models.Model): """用戶token表""" user = models.OneToOneField(to="UserInfo", on_delete=models.CASCADE) token = models.CharField(max_length=64) class Courses(models.Model): """ 課程表 """ name = models.CharField(verbose_name="課程名稱", max_length=32) course_img = models.CharField(verbose_name="課程圖片", max_length=64) level_choices = ( (1, "初級"), (2, "中級"), (3, "高級"), ) level = models.IntegerField(verbose_name="難度", choices=level_choices, default=1) def __str__(self): return self.name class CourseDetail(models.Model): """課程詳細表""" course = models.OneToOneField(to="Courses", on_delete=models.CASCADE) slogan = models.CharField(verbose_name="口號", max_length=255) why = models.CharField(verbose_name="爲何要學", max_length=255) recommend_courses = models.ManyToManyField(verbose_name="推薦課程", to="Courses", related_name="rc") # related_name設置反向查詢的字段,有多個關聯時指定某個字段進行反向查詢 def __str__(self): return "課程詳細:" + self.course.title class Chapter(models.Model): """ 課程章節表 """ num = models.IntegerField(verbose_name="章節") name = models.CharField(verbose_name="章節名稱", max_length=32) course = models.ForeignKey(verbose_name="所屬課程", to="Courses", related_name='coursechapters', on_delete=models.CASCADE) def __str__(self): return self.name
urls.pyapi
from django.contrib import admin from django.urls import path, include, re_path urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^api/(?P<version>\w+)/', include("api.urls")), ]
api/urls.pyide
from django.urls import re_path
from api.views import courses, account, micro
urlpatterns = [
re_path(r'^courses/$', courses.CoursesView.as_view({"get": "list"})),
re_path(r'^courses/(?P<pk>\d+)/', courses.CoursesView.as_view({"get": "retrieve"})),
re_path(r'^micro/$', micro.MicroView.as_view({"get": "list"})),
re_path(r'^login/$', account.LoginView.as_view()),
]
請求到來以後,都要執行dispatch方法,dispatch方法根據請求方式不一樣觸發不一樣的方法,返回不一樣的內容
url.py函數
1 from django.conf.urls import url, include 2 from api.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
views.pypost
1 from rest_framework.views import APIView 2 from rest_framework.response import Response 3 4 5 class TestView(APIView): 6 def dispatch(self, request, *args, **kwargs): 7 """ 8 請求到來以後,都要執行dispatch方法,dispatch方法根據請求方式不一樣觸發 get/post/put等方法 9 10 注意:dispatch方法有好多好多的功能 11 """ 12 return super().dispatch(request, *args, **kwargs) 13 14 def get(self, request, *args, **kwargs): 15 return Response('GET請求,響應內容') 16 17 def post(self, request, *args, **kwargs): 18 return Response('POST請求,響應內容') 19 20 def put(self, request, *args, **kwargs): 21 return Response('PUT請求,響應內容')
給micro添加須要認證才能訪問的權限學習
micro.py測試
# _*_ coding=utf-8 _*_ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.viewsets import ViewSetMixin from api.auth.auth import MicroAuth class MicroView(ViewSetMixin, APIView): # 給micro添加認證後才能訪問的組件 authentication_classes = [MicroAuth] def list(self, request, *args, **kwargs): ret = {'code': 1000, 'data': '學習中心'} return Response(ret)
auth.pyurl
# _*_ coding=utf-8 _*_ from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from api.models import * class MicroAuth(BaseAuthentication): """從token表讀取token進行認證""" def authenticate(self, request): token = request.query_params.get('token') obj = UserToken.objects.filter(token=token).first() if not obj: raise AuthenticationFailed({'code': 10001, 'error': '認證失敗'}) return (obj.user.user, obj)
全局設置:spa
上述操做中均是對單獨視圖進行特殊配置,若是想要對全局進行配置,則須要再配置文件中寫入便可
給course添加頻率限制,同一個IP,60秒內訪問不超過3次
•使用自定義類進行訪問頻率控制,繼承BaseThrottle類
myThrottle.py
import time from rest_framework.throttling import BaseThrottle class MyThrottle(BaseThrottle): """IP訪問頻率組件 限制60秒內訪問3次""" def __init__(self): self.history = None def allow_request(self, request, view): current_time = time.time() ip = request.META.get('REMOTE_ADDR') print(ip) if ip not in visit_code: # 若是是第一次訪問就把此ip的訪問時間存入visit_code中,返回True,不限制 visit_code[ip] = [current_time, ] return True # 若是不是第一次訪問,就獲取其ip的訪問時間[time1,time2..] history = visit_code.get(ip) self.history = history # print(history,visit_code) while history and history[-1] < current_time - 60: # 判斷第一次訪問時間和當前時間是否超過60s,超過則刪除 history.pop() if len(history) < 3: # history裏面的元素小於3個則把當前時間添加進去,方法True history.insert(0, current_time) return True # else: # 能夠不寫 # return False def wait(self): """須要等待多少時間才能訪問""" current_time = time.time() return 60 - (current_time - self.history[-1])
在CoursesView類添加訪問頻率組件
class CoursesView(ViewSetMixin, APIView): # 頻率訪問組件 throttle_classes = [MyThrottle,]
•使用rest framework內置頻率控制組件
myThrottle.py
from rest_framework.throttling import SimpleRateThrottle class VisitThrottle(SimpleRateThrottle): """內置ip頻率組件,須要在settings裏面設置參數""" scope = "visit_rate" def get_cache_key(self, request, view): return self.get_ident(request)
settings.py
REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASSES": ["api.myThrottle.VisitThrottle", ], "DEFAULT_THROTTLE_RATES": { "visit_rate": "5/m", # 這個參數就是頻率類中定義的那個參數scope, 其中第一個數字5表示5次, # 後面的m表示一分鐘,還有s,一秒, h, 一小時, d, 一天 } }
給TestView添加權限認證
views.py
# -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import BasePermission from rest_framework.request import Request class TestPermission(BasePermission): message = "權限驗證失敗" def has_permission(self, request, view): """ 判斷是否有權限訪問當前請求 Return `True` if permission is granted, `False` otherwise. :param request: :param view: :return: True有權限;False無權限 """ if request.user == "管理員": return True # GenericAPIView中get_object時調用 def has_object_permission(self, request, view, obj): """ 繼承GenericAPIView,並在其中使用get_object時獲取對象時,觸發單獨對象權限驗證 Return `True` if permission is granted, `False` otherwise. :param request: :param view: :param obj: :return: True有權限;False無權限 """ if request.user == "管理員": return True class TestView(APIView): # 認證的動做是由request.user觸發 # 添加權限 permission_classes = [TestPermission, ] def get(self, request, *args, **kwargs): # self.dispatch print(request.user) print(request.auth) return Response('GET請求,響應內容')
全局設置
settings.py
REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": [ "api.views.TestPermission", ], }
對用戶請求的數據進行序列化
a.自動生成字段
# _*_ coding=utf-8 _*_ from django.urls import re_path from api.views import courses urlpatterns = [ re_path(r'^courses/$', courses.CoursesView.as_view({"get": "list"})), ]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.viewsets import ViewSetMixin from rest_framework import serializers from api.models import * class CoursesSerializers(serializers.ModelSerializer): """課程序列化""" level = serializers.CharField(source='get_level_display') # 獲取choices的中文 class Meta: model = Course # 指定表 fields = "__all__" # 使用自動生成的字段 class CoursesView(ViewSetMixin, APIView): def list(self, request, *args, **kwargs): ret = {"code": 1000, "data": None} try: course_list = Course.objects.all() course_data = CoursesSerializers(instance=course_list, many=True) ret["data"] = course_data.data except Exception as e: ret["code"] = 1001 ret["error"] = "獲取失敗" return Response(ret)
b.使用自定義字段
# _*_ coding=utf-8 _*_ from django.urls import re_path from api.views import courses urlpatterns = [ re_path(r'^courses/$', courses.CoursesView.as_view({"get": "list"})), re_path(r'^courses/(?P<pk>\d+)/', courses.CoursesView.as_view({"get": "retrieve"})), ]
from rest_framework import serializers from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.viewsets import ViewSetMixin from api.serializers.courses_serializers import * from api.models import * class CourseDetailSerializers(serializers.ModelSerializer): """課程詳細序列化""" # OneToOne/fk/choice等字段查詢某一條記錄時適用: 自定義要序列化的字段,關聯的表:表名.字段, name = serializers.CharField(source='course.name') level = serializers.CharField(source='course.get_level_display') # 獲取choice類型對應的中文 # ManyToMany,fk查詢多條記錄適用: recommend_courses = serializers.SerializerMethodField() chapters = serializers.SerializerMethodField() class Meta: model = CourseDetail # 添加自定義字段 fields = ['name', 'level', 'recommend_courses', 'chapters'] def get_recommend_courses(self, obj): # 獲取全部的課程,obj指的是CourseDetail,recommends字段數據爲此函數的返回值 course_list = obj.recommend_course.all() return [{"id": i.id, "title": i.name} for i in course_list] def get_chapters(self, obj): # 反向查詢時若是定義了related_name,要使用related_name的值進行查詢 chapters = obj.course.coursechapters.all() return [{"id": i.id, "name": i.name} for i in chapters] class CoursesView(ViewSetMixin, APIView): def list(self, request, *args, **kwargs): ret = {"code": 1000, "data": None} try: course_list = Course.objects.all() course_data = CoursesSerializers(instance=course_list, many=True) ret["data"] = course_data.data except Exception as e: ret["code"] = 1001 ret["error"] = "獲取失敗" return Response(ret) def retrieve(self, request, *args, **kwargs): ret = {"code": 1000, "data": None} try: # 課程id pk = kwargs.get("pk") # 課程詳細對象 obj = CourseDetail.objects.filter(course_id=pk).first() course_detail = CourseDetailSerializers(instance=obj, many=False) ret["data"] = course_detail.data except Exception as e: ret["code"] = 1001 ret["error"] = "獲取失敗" return Response(ret)
設置頁碼進行分頁
# _*_ coding=utf-8 _*_ from django.urls import re_path from api.views import courses urlpatterns = [ re_path(r'^courses/$', courses.CoursesView.as_view({"get": "list"})), re_path(r'^courses/(?P<pk>\d+)/', courses.CoursesView.as_view({"get": "retrieve"})), ]
# -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from api import models from rest_framework.pagination import PageNumberPagination class MyPagination(PageNumberPagination): # 默認每頁顯示的數據條數 page_size = 1 # 獲取URL參數中設置的每頁顯示數據條數 page_size_query_param = 'page_size' # 獲取URL參數中傳入的頁碼key page_query_param = 'page' # 最大支持的每頁顯示的數據條數 max_page_size = 1 class CourseSerializer(serializers.ModelSerializer): class Meta: model = models.Course fields = "__all__" class CoursesViewSet(APIView): def list(self, request, *args, **kwargs): course_list = models.Course.objects.all().order_by('-id') # 實例化分頁對象,獲取數據庫中的分頁數據 paginator = MyPagination() page_course_list = paginator.paginate_queryset(course_list, self.request, view=self) # 序列化對象 serializer = CourseSerializer(page_user_list, many=True) # 生成分頁和數據 response = paginator.get_paginated_response(serializer.data) return response
使用自動生成url
urls.py
from rest_framework import routers from api.views import * router = routers.DefaultRouter() router.register('courses', CoursesViewSet)
便捷使用分頁器
views.py
from rest_framework import viewsets from rest_framework import serializers from api.models import * class CoursesSerializers(serializers.ModelSerializer): """課程序列化""" level = serializers.CharField(source='get_level_display') class Meta: model = Courses fields = "__all__" class CoursesViewSet(viewsets.ModelViewSet): # 指定已經寫好的分頁器 pagination_class = MyPagination queryset = Courses.objects.all().order_by('id') # 使用分頁器要排序 serializer_class = CoursesSerializersModel