REST framework API 知识梳理
规范:
域名:
api部署在专用的域名上(跨域)
版本号(可以在url上也可以在请求头上)
路径:
URL的api接口要写成名词
method:
CBV 这种方式就是 restful 规范提供接口的方式
['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
GET /collection:返回资源对象的列表(数组) GET /collection/resource:返回单个资源对象 POST /collection:返回新生成的资源对象 PUT /collection/resource:返回完整的资源对象 PATCH /collection/resource:返回完整的资源对象 DELETE /collection/resource:返回一个空文档
返回值:
返回值要有状态码
content_type = 'application/json'
错误时: 也要返回状态码
过滤:
通过URL传递搜索条件
VirtualENV:
# 建立 不拷贝原本的环境
virtualenv --no-site-packages venv
# 激活
进入 venv/Scripts/ 中直接执行 activate
# 退出
deactivate
Django REST framework 框架
安装:
pip install djangorestframework
APIView:
本质:就是继承django的View
版本:
源码: 找到就实例化,没找到就返回空,这里class 不是复数所以只能写一个类
if self.versioning_class is None: return (None, None) scheme = self.versioning_class() # 这里内部应该有个个 determine_version 方法 return (scheme.determine_version(request, *args, **kwargs), scheme)
源码默认提供的方法(共五个,都有示例):
# 导入来查看源码
from rest_framework.versioning import BaseVersioning
QueryParameterVersioning # 这是URL get方式传参默认 使用version关键字
示例:
# 浏览器访问使用默认关键字 http://127.0.0.1:8000/user/?version=v1 class UsersView(APIView): # 这里指定获取版本使用的类,必须导入QueryParameterVersioning versioning_class = QueryParameterVersioning def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} # 打印获取的版本号 print(request.version) return HttpResponse(json.dumps(response_status))
URLPathVersioning # 这是通过 URL 传递版本号
示例:
# 浏览器访问地址 http://127.0.0.1:8000/user/v100 # urls.py文件 url(r'^user/(?P<version>\w+)', views.UsersView.as_view()) # 源码中还提供了这种方式限制版本号的方式 url(r'^(?P<version>[v1|v2]+)/users/$' class UsersView(APIView): versioning_class = URLPathVersioning def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} print(request.version) return HttpResponse(json.dumps(response_status))
在配置文件中配置全局使用
REST_FRAMEWORK = { # "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.<使用的类>" 下面示例: # "VERSION_PARAM": "version" # 默认关键字 # "DEFAULT_VERSION": "v1" # 默认的版本 # "ALLOWED_VERSIONS": "v1" # 允许的版本 多个使用列表方法 ["v1", "v2"] "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning" }
rest_framework 默认错误显示页面 需要在 django APP中注册
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', # 这里注册rest_framework 'rest_framework' ]
这里进行反向生成路由
# urls.py 文件 url(r'^user/(?P<version>\w+)', views.UsersView.as_view(), name="xxx"), # 类中代码 class UsersView(APIView): versioning_class = URLPathVersioning def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} print(request.version) # 下面这条就是,需要传入request对象 print(request.versioning_scheme.reverse(viewname='xxx', request=request)) return HttpResponse(json.dumps(response_status))
认证:
导入查看默认的认证类:
from rest_framework.authentication import BaseAuthentication
默认就有两个认证类:[<class 'rest_framework.authentication.SessionAuthentication'>, <class 'rest_framework.authentication.BasicAuthentication'>] def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} # 直接打印 self.authentication_classes 查看 print(self.authentication_classes) return HttpResponse(json.dumps(response_status))
源码流程:
initialize_request 通过 get_authenticators() 获取所有的认证类封装到request对象中
initial 通过 self.perform_authentication(request) 执行 调用 request.user 方法执行认证
request.user 执行 self._authenticate() 方法:
循环所有的认证类的对象,调用对象的 authenticate(self) 方法
如果认证失败会raise错误,认证成功返回的是元组形式(user, None)
后续不在执行, 返回None没有报错 则后续认证器继续认证
更改为认证未通过用户显示 Anymouns的问题:
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, # 默认未认证用户名 'UNAUTHENTICATED_TOKEN': None, # 默认未认证TOKEN }
自定义认证:
TK_LIST = [ 'asdasdas', 'asdasdasdsad' ] class CustomAuthentication(BaseAuthentication): def authenticate(self, request): # 通过query_params来获取URL传递的参数 tk = request.query_params.get('tk') if tk in TK_LIST: print('11') return ('alex', None) # 这种方式从数据库取数据验证用户 # token_obj = models.Token.objects.filter(token=tk).first() # if token_obj: # return (token_obj.user, token_obj) # 如果认证失败不继续下个认证器则,直接抛出错误,否则返回None raise exceptions.AuthenticationFailed("认证失败") # return (None,None) class UsersView(APIView): # 设置认证器 authentication_classes = [CustomAuthentication,] def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} print(self.authentication_classes) return HttpResponse(json.dumps(response_status)) # ----------------- 认证视图操作 ------------- class AuthPage(APIView): def post(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': None} # 通过 request.data 获取用户post传递的数据 user = request.data.get('user') pwd = request.data.get('pwd') user_obj = models.UserInfo.objects.filter(user=user, pwd=pwd).first() if user_obj: tk = self.gen_token(user) models.Token.objects.update_or_create(user=user_obj, defaults={'token': tk}) ret['code'] = 1001 ret['token'] = tk else: ret['msg'] = "用户名或密码错误" return JsonResponse(ret) @staticmethod def gen_token(username): ctime = str(time.time()) hash = hashlib.md5(username.encode('utf-8')) hash.update(ctime.encode('utf-8')) return hash.hexdigest()
认证响应头,basic验证:
# 加上这个会出现浏览器弹个窗口认证,需要base64解密才能看见用户名密码
def authenticate_header(self, request): return 'Basic realm="api"'
权限:
源码流程基本同上面的认证一致.也是拿到权限类,执行其中的 has_permission(self, request, view)
返回 True 表示有权限,返回 False 没有权限,
接收的参数中有 request 可以点出用户的相关属性.
代码示例:
class CustomPermission(BasePermission): # 这个字段是设置默认没有权限的提示 message = "无权限" # 实现 has_permission 方法 def has_permission(self, request, view): # 这里自定义权限条件 # 如果想使用原本的request对象, request._request # request._request.method 获取请求的方法 return True class UsersView(APIView): # 这里使用权限类 permission_classes = [CustomPermission,] def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} # 打印默认使用的权限类,通过这个可以找到源码默认提供的权限类 print(self.permission_classes) return HttpResponse(json.dumps(response_status)) 注意: # from rest_framework.views import APIView 如果视图类继承的是APIViews 则只会执行 has_permission 方法. # from rest_framework.generics import GenericAPIView 只有在继承 GenericAPIView 时才会执行 has_object_permission 方法
节流(访问次数限制):
源码流程还是基本同上面一致,拿到类,然后去执行类中的allow_request 方法
返回 True 不限制, 返回 False 则不能访问并执行wait方法,返回等待多久
默认没有限制(没有默认的类)
查看源码提供的方法:
# from rest_framework.throttling import BaseThrottle
简单代码示例(根据IP限制次数):
# settings.py 文件中 REST_FRAMEWORK = { "DEFAULT_THROTTLE_RATES": { 'anon': '5/m' # 这里配置访问次数限制 每分钟5次 } } # 这里继承的 SimpleRateThrottle class CustomThrottle(SimpleRateThrottle): scope = 'anon' # 配置文件中的字典key关键字 # 此方法,仅仅去掉了原本的 验证,未做任何修改 def get_cache_key(self, request, view): # 被去掉的内容 #if request.user.is_authenticated: # return None # Only throttle unauthenticated requests. return self.cache_format % { 'scope': self.scope, 'ident': self.get_ident(request) } class UsersView(APIView): # 配置使用节流器 throttle_classes = [CustomThrottle,] def get(self, request, *args, **kwargs): response_status = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} return HttpResponse(json.dumps(response_status))
allow_request 中的操作:
- 获取访问频率 __init__(self) - 获取当前用户的唯一标识 get_cache_key(self, request, view) - 根据用户标识,获取所有的访问记录 self.history = self.cache.get(self.key, []) - 获取当前时间 self.now = self.timer() - 循环比对当前访问的时间和列表的中进行比较,并pop出过期的记录 - 计算访问次数,如果大于次数限制,执行 throttle_failure 返回False, 小于的话 执行 throttle_success 返回True - 如果返回 False 会继续执行wait 方法,返回还有多久能访问
实现针对用户的节流:
重写 allow_request中 self.key 让它直接等于一个值.删除原本的self.key # self.key = request.user.user 例如直接等于 用户名 self.key = self.get_cache_key(request, view) if self.key is None: return True
解析器:
根据请求头 content-type 选择对应的解析器就请求体内容进行处理。
# 此处为详细.. 参考老师的blog
# http://www.cnblogs.com/wupeiqi/articles/7805382.html
序列化:
导入包:
from rest_framework import serializers from rest_framework.response import Response from . import models
简单的序列化示例:
class UserSerialize(serializers.Serializer): user = serializers.CharField() pwd = serializers.CharField() email = serializers.CharField() # 跨表显示:括号内 使用source = class UsersView(APIView): def get(self, request, *args, **kwargs): response = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} user_list = models.UserInfo.objects.all() ser = UserSerialize(instance=user_list, many=True) # many表示对象是多个,单个对象写False response['data'] = ser.data # ser.data 是有序字典 # return HttpResponse(response) # Django的返回方法 return Response(response) # restful 的返回数据方法 # http://127.0.0.1:8000/user/?format=json 加上 json 会直接显示json数据
关于 restful 自带的 Response :
# http://127.0.0.1:8000/user/?format=json 加上 json 会直接显示json数据 # url(r'^user\.(?P<format>\w+)', views.UsersView.as_view()), 或者修改 URL # 访问的时候直接 输入: http://127.0.0.1:8000/user.json
关于 source 跨表的一些东西:
source 不只是跨表查询, 还可以传入当前表的字段来调取字段的一些方法,比如 get_字段名_display
甚至可以直接获取MTM字段的值,可以直接 .all 不加 括号 源码中自动加括号,但是不能传参
requests模块发送post请求:
import requests res = requests.post(url='http://127.0.0.1:8000/user.json', data={ 'user': 'abc', 'pwd': '12312', 'email': '123123@qq.com' }) print(res.text)
序列化和数据验证:
class UserSerialize(serializers.Serializer): user = serializers.CharField() pwd = serializers.CharField() email = serializers.CharField(required=False) # required 表示是否是必填字段 # 自定义错误信息,error_messages = {'required':'<信息>'} # 自定义验证 validators = [PasswordValidator(666)] 可以写类,下面示例 class UsersView(APIView): def get(self, request, *args, **kwargs): response = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} user_list = models.UserInfo.objects.all() ser = UserSerialize(instance=user_list, many=True) response['data'] = ser.data return Response(response) def post(self, request, *args, **kwargs): ser = UserSerialize(data=request.data) if ser.is_valid(): # 判断是否是正确的数据 print(ser.validated_data) # 打印出正确的数据 else: print(ser.errors) # 打印出错误信息 return Response('...')
自定义validators验证的类:
class PasswordValidator(object): # __init__不是必须的,可以在传入validators时给类加括号传入参数给 __Init__ def __init__(self, base): self.base = base def __call__(self, value): if value != self.base: message = 'This field must be %s.' % self.base raise serializers.ValidationError(message)
基于Model序列化:
基本代码示例:
# 非常类似 django的modelform class UserSerialize(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" # 可定制显示几个字段,必须列表形式
反向生成URL地址:
# urls.py 中 url(r'^test/(?P<pk>\d+)', views.UsersView.as_view(), name='xxx'), # 类中需要加的参数 class UsersView(APIView): def get(self, request, *args, **kwargs): response = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} user_list = models.UserInfo.objects.all() # context={'request': request} 反向生成URL使用 ser = UserSerialize(instance=user_list, many=True, context={'request': request}) response['data'] = ser.data return Response(response) # 序列化类自定义字段 class UserSerialize(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='xxx') # 反向生成url class Meta: model = models.UserInfo fields = "__all__"
自定义错误信息,自定义验证
class UserSerialize(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='xxx') # 反向生成url class Meta: model = models.UserInfo fields = "__all__" # 对字段自定义 extra_kwargs = { 'user':{'min_length':6}, 'pwd': {'validators': []} }
按深度取 FK, M2M 的信息
class UserSerialize(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='xxx') # 反向生成url class Meta: model = models.UserInfo fields = "__all__" # 按深度取FK , M2M, 2表示深度最大为10 depth = 2
基于HyperlinkedModelSerializer的全自动生成url
# urls.py文件 # 这里的name = '<表名>-detail' url(r'^test/(?P<pk>\d+)', views.UsersView.as_view(), name='userinfo-detail'), # 序列化类, 只要继承 HyperlinkedModelSerializer 就行了 class UserSerialize(serializers.HyperlinkedModelSerializer): class Meta: model = models.UserInfo fields = "__all__"
分页:
# 此处为详细.. 参考老师的blog
# http://www.cnblogs.com/wupeiqi/articles/7805382.html
路由和视图:
通过URL传参来判断取多少数据,称之为手动档
继承 GenericAPIView (GenericAPIView是继承 APIView的)
# 当继承后的序列化方式 class UsersView(GenericAPIView): # 配置查询的类 queryset = models.UserInfo.objects.all() # 配置序列化类 serializer_class = UserSerialize def get(self, request, *args, **kwargs): response = {'code': 200, 'error_msg': None, 'content_type': 'application/json', 'data': None} # 获取查询的东西 user_list = self.get_queryset() # 获取序列化类,传入数据 ser = self.get_serializer(instance=user_list, many=True) return Response(ser.data)
继承 GenericViewSet 时
# urls.py 中必须指定当 get请求时 执行list视图函数, post同理 urls.py 中的 as_view() 内必须传参({'get':'list','post':'add'}) # url(r'^user/', views.UsersView.as_view({'get':'list', 'post':'add'})), # 其他跟 GenericAPIView 基本一致 # from rest_framework.viewsets import mixins # 可以通过直接继承mixins中的东西,来实现增删查改等操作
直接继承 ModelViewSet 时(半自动路由):
# urls.py 文件: url(r'^user/', views.UsersView.as_view({'get':'list', 'post':'add'})), # 类直接这样写,直接可以实现增删查改,需要urls.py中支持 class UsersView(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = UserSerialize
全自动路由实现:
# urls.py文件中: from app01 import views from rest_framework.routers import DefaultRouter route = DefaultRouter() # 括号内第一个参数为路由前缀,第二个为 view 中的视图 route.register('userInfo', views.UsersView) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include(route.urls)), ] # Views.py 文件中, 视图类必须继承 ModelViewSet class UsersView(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = UserSerialize
源码:
# dispatch中 initialize_request: 二次封装request对象(这里通过 Request 类来封装的,加了一些东西, 加入了解析器, 认证器, 选择器(选择解析器)等) initial: get_format_suffix # 获取URL后缀 perform_content_negotiation # 选择器(根据用户请求选择解析器) determine_version # 获取版本 perform_authentication # 认证处理 check_permissions # 权限处理 check_throttles # 节流(限制访问次数) 反射: 通过反射找到对应的视图函数,并执行
django_restframework 请求生命周期:
中间件,路由系统,视图(对request进行二次封装,然后版本,认证,权限,节流,执行视图方法, 最后处理响应内容)
附加内容:
状态码: 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
浙公网安备 33010602011771号