Django rest framework 简易使用方法

Django rest framework 工具包做API非常方便。

下面简单说一下几个功能的实现方法。

实现功能为,匿名用户访问首页一分钟能访问3次,登录用户一分钟访问6次,只有登录用户才能访问order页面。

第一步,注册app

 1 INSTALLED_APPS = [
 2     'django.contrib.admin',
 3     'django.contrib.auth',
 4     'django.contrib.contenttypes',
 5     'django.contrib.sessions',
 6     'django.contrib.messages',
 7     'django.contrib.staticfiles',
 8     'app.apps.AppConfig',
 9     'rest_framework',  #注册
10 ]

settings文件注册app

第二步,定义URL,注意url路径最好使用名词。我们这里注册三个视图函数的url,实现验证,首页和定单页面。

 1 from django.conf.urls import url
 2 from django.contrib import admin
 3 from app import views
 4 
 5 urlpatterns = [
 6     url(r'^admin/', admin.site.urls),
 7     url(r'^auth/', views.AuthView.as_view()),  #验证
 8     url(r'^index/', views.IndexView.as_view()), #首页
 9     url(r'^order/', views.OrderView.as_view()),  #定单
10 ] 

url文件设置路由

第三步,auth视图函数

 1 from rest_framework.views import APIView
 2 from rest_framework.request import Request
 3 from django.http import JsonResponse,HttpResponse
 4 
 5 from app.utils.commons import gen_token
 6 from app.utils.auth import LuffyAuthentication
 7 from app.utils.throttle import LuffyAnonRateThrottle,LuffyUserRateThrottle
 8 from app.utils.permission import LuffyPermission
 9 from . import models
10 
11 class AuthView(APIView):
12 
13     """
14     认证相关视图
15     由于继承了APIView,所以csrf就没有了,具体的源代码只是有一个装饰器,
16     加上了csrf_exempt装饰器,屏蔽了csrf
17     写法是在return的时候csrf_exempt(view) 和@使用装饰器效果是一样的,这种写法还可以写在url路由中。
18     """
19     def post(self,request,*args,**kwargs):
20         """
21         用户登录功能
22         :param request:
23         :param args:
24         :param kwargs:
25         :return:
26         """
27         ret = {'code': 1000, 'msg': None}
28         # 默认要返回的信息
29         user = request.data.get('username')
30         # 这里的request已经不是原来的request了
31         pwd = request.data.get('password')
32         user_obj = models.UserInfo.objects.filter(user=user, pwd=pwd).first()
33         if user_obj:
34             tk = gen_token(user)  #返回一个哈希过得字符串
35             #进行token验证
36             models.Token.objects.update_or_create(user=user_obj, defaults={'token': tk})
37             # 数据库存入一个token信息
38             ret['code'] = 1001
39             ret['token'] = tk
40         else:
41             ret['msg'] = "用户名或密码错误"
42         return JsonResponse(ret)

上面的代码主要是实现了一个验证的功能,通过gen_token函数来验证,并存入数据库信息。

gen_token单独写到一个utils目录下的auth.py文件中。代码如下:

1 def gen_token(username):
2     import time
3     import hashlib
4     ctime = str(time.time())
5     hash = hashlib.md5(username.encode('utf-8'))
6     hash.update(ctime.encode('utf-8'))
7     return hash.hexdigest()

通过时间和哈希等生成一个不重复的字符串。

第四步,index视图函数

 1 class IndexView(APIView):
 2     """
 3     用户认证
 4         http://127.0.0.1:8001/v1/index/?tk=sdfasdfasdfasdfasdfasdf
 5         获取用户传入的Token
 6 
 7     首页限制:request.user
 8         匿名:5/m
 9         用户:10/m
10     """
11     authentication_classes = [LuffyAuthentication,]
12     #认证成功返回一个用户名,一个对象,不成功就是None
13     throttle_classes = [LuffyAnonRateThrottle,LuffyUserRateThrottle]
14     #访问次数限制,如果合格都为True
15     def get(self,request,*args,**kwargs):
16         return HttpResponse('首页')

同样,将LuffyAuthenticationLuffyAnonRateThrottle,LuffyUserRateThrottle写到了utils目录下。代码如下:

auth.py :

 1 from rest_framework.authentication import BaseAuthentication
 2 from rest_framework import exceptions
 3 from app import models
 4 class LuffyAuthentication(BaseAuthentication):
 5     def authenticate(self, request):
 6         tk = request.query_params.get('tk')
 7         if not tk:
 8             return (None,None)
 9             # raise exceptions.AuthenticationFailed('认证失败')
10 
11         token_obj = models.Token.objects.filter(token=tk).first()
12         if not token_obj:
13             return (None,None)
14 
15         return (token_obj.user,token_obj)

验证是否为登录用户,如果之前没有登陆过,则将token信息存到数据库

throttle.py :

 1 from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
 2 
 3 
 4 class LuffyAnonRateThrottle(SimpleRateThrottle):
 5 
 6     scope = "luffy_anon"
 7 
 8     def allow_request(self, request, view):
 9         """
10         Return `True` if the request should be allowed, `False` otherwise.
11         """
12         if request.user:
13             return True
14 
15         # 获取当前访问用户的唯一标识
16         self.key = self.get_cache_key(request, view)
17         # 根据当前用户的唯一标识,获取所有访问记录
18         # [1511312683.7824545, 1511312682.7824545, 1511312681.7824545]
19         self.history = self.cache.get(self.key, [])
20         # 获取当前时间
21         self.now = self.timer()
22 
23         # Drop any requests from the history which have now passed the
24         # throttle duration
25         while self.history and self.history[-1] <= self.now - self.duration:
26             self.history.pop()
27         if len(self.history) >= self.num_requests:   #判断访问次数是否大于限制次数
28             return self.throttle_failure()
29         return self.throttle_success()  #返回True
30 
31     def get_cache_key(self, request, view):
32         return 'throttle_%(scope)s_%(ident)s' % {
33             'scope': self.scope,
34             'ident': self.get_ident(request),
35 
36             # 判断是否为代理等等
37 
38         }
39 
40 class LuffyUserRateThrottle(SimpleRateThrottle):
41     scope = "luffy_user"
42     def allow_request(self, request, view):
43         """
44         Return `True` if the request should be allowed, `False` otherwise.
45         """
46         if not request.user:   #判断登录直接返回True
47             return True
48         # 获取当前访问用户的唯一标识
49         # 用户对所有页面
50         # self.key = request.user.user
51 
52         self.key = request.user.user + view.__class__.__name__
53         # 用户对单页面的访问限制
54 
55         # 根据当前用户的唯一标识,获取所有访问记录
56         # [1511312683.7824545, 1511312682.7824545, 1511312681.7824545]
57         self.history = self.cache.get(self.key, [])
58         # 获取当前时间
59         self.now = self.timer()
60 
61         # Drop any requests from the history which have now passed the
62         # throttle duration
63         while self.history and self.history[-1] <= self.now - self.duration:
64             self.history.pop()
65         if len(self.history) >= self.num_requests:   #访问次数的限制
66             return self.throttle_failure()
67         return self.throttle_success()   #返回True

限制匿名用户和登录用户的访问次数,需要从settings中的配置拿去配置信息。

permission.py

 1 from rest_framework.permissions import BasePermission
 2 
 3 
 4 class LuffyPermission(BasePermission):
 5     def has_permission(self, request, view):
 6         """
 7         Return `True` if permission is granted, `False` otherwise.
 8         """
 9         if request.user:
10             return True
11         return False

权限控制

第五步,order视图函数

 1 class OrderView(APIView):
 2     """
 3     订单页面:只有登录成功后才能访问
 4         - 认证(匿名和用户)
 5         - 权限(用户)
 6         - 限制()
 7     """
 8     authentication_classes = [LuffyAuthentication, ]
 9     permission_classes = [LuffyPermission,] #登录就返回True
10     throttle_classes = [LuffyAnonRateThrottle, LuffyUserRateThrottle]
11 
12     def get(self,request,*args,**kwargs):
13 
14         return HttpResponse('订单')

第六步,settings配置

1 REST_FRAMEWORK = {
2     'UNAUTHENTICATED_USER': None,
3     'UNAUTHENTICATED_TOKEN': None,
4     "DEFAULT_THROTTLE_RATES": {
5         'luffy_anon': '3/m', #匿名用户一分钟访问3次
6         'luffy_user': '6/m'  #登录用户一分钟访问6次
7     },
8 }

最后,实现功能为,匿名用户访问首页一分钟能访问3次,登录用户一分钟访问6次,只有登录用户才能访问order页面。

学习Django rest framework需要随时查看源代码,判断源代码的逻辑思路来自定义自己的功能,如此学习效率极高。