## 什么是restful
* REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
* REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
* 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
* 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
## 什么是API
1、什么是API?
答:API就是接口,提供的url。接口有两个用途:
* \- 为别人提供服务
* \- 前后端分离,一个写vue,一个写后端,他们之间都是通过ajax请求
## restful API设计规范
* API与用户的通信协议,总是使用HTTPS协议。
* 域名
* https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
* https://example.org/api/ API很简单
* 版本
* URL,如:https://api.example.com/v1/
* 请求头 跨域时,引发发送多次请求
* 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
* https://api.example.com/v1/zoos
* https://api.example.com/v1/animals
* https://api.example.com/v1/employees
* method
* GET :从服务器取出资源(一项或多项)
* POST :在服务器新建一个资源
* PUT :在服务器更新资源(客户端提供改变后的完整资源)
* PATCH :在服务器更新资源(客户端提供改变的属性)
* DELETE :从服务器删除资源
* 过滤,通过在url上传参的形式传递搜索条件
* https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
* https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
* https://api.example.com/v1/zoos?page=2&per\_page=100:指定第几页,以及每页的记录数
* https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
* https://api.example.com/v1/zoos?animal\_type\_id=1:指定筛选条件
* 状态码
```
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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
```
* 错误处理,状态码是4xx时,应返回错误信息,error当做key。
~~~
{
error: "Invalid API key"
}
~~~
* 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
~~~
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
~~~
* Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
## 基于Django实现restful api
参考博客:https://www.cnblogs.com/wusir66/p/10016584.html
## 基于Django Rest Framework框架实现
PS:以下介绍的使用方式都是一些常用的,还有一些方式使用较少,在此不做介绍。
### 一、自定义用户认证
在models.py的UserInfo表中创建一些数据
```
from django.db import models
class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64)
class UserToken(models.Model):
user = models.OneToOneField(to='UserInfo')
token = models.CharField(max_length=64)
models.py
```
```
from django.http import JsonResponse
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
#创建token字符串
def md5(user):
ctime = str(time.time())
m = hashlib.md5(bytes(user,encoding='utf-8'))
m.update(bytes(ctime,encoding='utf-8'))
return m.hexdigest()
#找到指定用户给其token值
class AuthView(APIView):
authentication_classes = []
def post(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None}
try:
name = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = UserInfo.objects.filter(username=name,password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
token = md5(name)
UserToken.objects.update_or_create(user=obj,defaults={'token':token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
#利用token值来进行认证
class OrderView(APIView):
def get(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None,'data':None}
order = {'goods':'food'}
try:
ret['data'] = order
except Exception as e:
ret['msg'] = '有问题'
return JsonResponse(ret)
view.py
```
在app目录下创建一个rest\_utils的文件夹
```
from rest_framework.authentication import BaseAuthentication
from app.models import *
from rest_framework import exceptions
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request._request.GET.get('token')
obj = UserToken.objects.filter(token=token).first()
if not obj:
raise exceptions.AuthenticationFailed('用户未认证')
return (obj.user,obj)
def authenticate_header(self, request):
pass
auth.py(具体认证代码)
```
配置文件
~~~
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':['app.rest_utils.auth.MyAuthentication',],
}
~~~
如果有某些类不需要使用认证,可以在类中加上以下代码
~~~
authentication_classes = []
~~~
源码大致流程
```
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
第一步:对request进行加工(添加数据)
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
#第二步:
#处理版权信息
#认证
#权限
#请求用户进行访问频率的限制
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 第三步、执行:get/post/put/delete函数
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
#第四步、 对返回结果再次进行加工
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
```
源码具体流程
请求来了先走dispatch方法做分发
**1、对request进行加工(添加数据)**
**a、首先 request = self.initialize\_request(request, \*args, \*\*kwargs)点进去,会发现:在Request里面多加了四个,如下**
```
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
#把请求弄成一个字典返回
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(), #解析数据,默认的有三种方式,可点进去看
#self.get_authenticator优先找自己的,没有就找父类的
authenticators=self.get_authenticators(), #获取认证相关的所有类并实例化,传入request对象供Request使用
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
```
**b、获取认证相关的类的具体 authenticators=self.get\_authenticators()**
~~~
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
#返回的是对象列表
return [auth() for auth in self.authentication_classes] #[SessionAuthentication,BaseAuthentication]
~~~
**c、查看认证的类:self.authentication\_classes**
~~~
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #默认的,如果自己有会优先执行自己的
~~~
**d、接着走进api\_settings**
```
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) #点击继承的DEFAULTS类
DEFAULTS类
DEFAULTS = {
# Base API policies
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication', #这时候就找到了他默认认证的类了,可以导入看看
'rest_framework.authentication.BasicAuthentication'
),
```
**e、导入了类看看类里面具体干了什么**
~~~
from rest_framework.authentication import SessionAuthentication
from rest_framework.authentication import BaseAuthentication
~~~
**f、看到里面有个authenticate方法和authenticate\_header方法**
```
class BaseAuthentication(object):
"""
All authentication classes should extend BaseAuthentication.
"""
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.")
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
```
**具体处理认证,从headers里面能获取用户名和密码**
```
class BasicAuthentication(BaseAuthentication):
"""
HTTP Basic authentication against username/password.
"""
www_authenticate_realm = 'api'
def authenticate(self, request):
"""
Returns a `User` if a correct username and password have been supplied
using HTTP Basic authentication. Otherwise returns `None`.
"""
auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != b'basic':
return None #返回none不处理。让下一个处理
if len(auth) == 1:
msg = _('Invalid basic header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid basic header. Credentials string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':') #用partition切割冒号也包括
except (TypeError, UnicodeDecodeError, binascii.Error):
msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
raise exceptions.AuthenticationFailed(msg)
userid, password = auth_parts[0], auth_parts[2] # 返回用户和密码
return self.authenticate_credentials(userid, password, request)
def authenticate_credentials(self, userid, password, request=None):
"""
Authenticate the userid and password against username and password
with optional request for context.
"""
credentials = {
get_user_model().USERNAME_FIELD: userid,
'password': password
}
user = authenticate(request=request, **credentials)
if user is None:
raise exceptions.AuthenticationFailed(_('Invalid username/password.'))
if not user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
return (user, None)
def authenticate_header(self, request):
return 'Basic realm="%s"' % self.www_authenticate_realm
```
**g、当然restfulframework默认定义了两个类。我们也可以自定制类,自己有就用自己的了,自己没有就去找父类的了,但是里面必须实现authenticate方法,不然会报错。**
**2、加工完request之后的操作**
* 处理版权信息
* 认证
* 权限
* 请求用户进行访问频率的限制
认证流程
**a、首先 self.initial(request, \*args, \*\*kwargs)可以看到做了以下操作**
```
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
#2.1 处理版本信息
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
#2.2 认证
self.perform_authentication(request)
# 2.3 权限
self.check_permissions(request)
# 2.4 请求用户进行访问频率的限制
self.check_throttles(request)
```
** b、我们先来看认证,self.perform\_authentication(request) 具体干了什么,按住ctrl点击进去**
```
def perform_authentication(self, request):
"""
Perform authentication on the incoming request.
Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user #执行request的user,这是的request已经是加工后的request了
```
**c、那么我们可以从视图里面导入一下Request,找到request对象的user方法**
~~~
from rest_framework.views import Request
~~~
```
@property
def user(self):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes provided to the request.
"""
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate() #
return self._user #返回user
```
**d、执行self.\_authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)**
```
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
#循环对象列表
for authenticator in self.authenticators:
try:
#执行每一个对象的authenticate 方法
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple #返回一个元组,user,和auth,赋给了self,
# 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
return
self._not_authenticated()
```
**e、在user\_auth\_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法**
**f、如果用户没有认证成功:self.\_not\_authenticated()**
```
def _not_authenticated(self):
"""
Set authenticator, user & authtoken representing an unauthenticated request.
Defaults are None, AnonymousUser & None.
"""
#如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None #
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser
else:
self.user = None # None 表示跳过该认证
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN() # 默认值为:None
else:
self.auth = None
# (user, token)
# 表示验证通过并设置用户名和Token;
# AuthenticationFailed异常
```
**3、执行get/post/delete等方法**
**4、对返回结果在进行加工**
### 二、自定义权限
在app目录下创建一个rest\_utils的文件夹
```
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
message = '必须是svip才能访问'
def has_permission(self,request,view):
if request.user.user_type != 3:
return False
return True
permission.py
```
配置文件
~~~
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ['app.rest_utils.permission.MyPermission', ],
}
~~~
如果有某些类不需要使用权限,可以在类中加上以下代码
~~~
permission_classes = []
~~~
### 三、自定义节流
在app目录下创建一个rest\_utils的文件夹
```
from rest_framework.throttling import BaseThrottle
import time
VISIT_RECORD = {}
class VisitThrottle(BaseThrottle):
def __init__(self):
self.history = None
def allow_request(self,request,view):
# 1. 获取用户IP
remote_addr = self.get_ident(request)
ctime = time.time()
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime,]
return True
history = VISIT_RECORD.get(remote_addr)
self.history = history
while history and history[-1] < ctime - 60:
history.pop()
if len(history) < 3:
history.insert(0,ctime)
return True
# return True # 表示可以继续访问
# return False # 表示访问频率太高,被限制
def wait(self):
# 还需要等多少秒才能访问
ctime = time.time()
return 60 - (ctime - self.history[-1])
throttle.py
```
配置文件
~~~
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": ["app.rest_utils.throttle.VisitThrottle"],
}
~~~
如果有某些类不需要使用节流,可以在类中加上以下代码
~~~
throttle_classes = []
~~~
### 四、版本
配置文件
~~~
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'],
"VERSION_PARAM":'version',
}
~~~
路由
~~~
from django.conf.urls import url
from app.views import *
urlpatterns = [
url('^(?P<version>[v1|v2]+)/orderview/$',OrderView.as_view(),name='wusir'),
]
~~~
视图
```
from django.http import JsonResponse
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
def md5(user):
ctime = str(time.time())
m = hashlib.md5(bytes(user,encoding='utf-8'))
m.update(bytes(ctime,encoding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
authentication_classes = []
permission_classes = []
def post(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None}
try:
name = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = UserInfo.objects.filter(username=name,password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
token = md5(name)
UserToken.objects.update_or_create(user=obj,defaults={'token':token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
class OrderView(APIView):
def get(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None,'data':None}
order = {'goods':'food'}
# 获得版本信息
print(request.version)
# 获取处理版本的对象
print(request.versioning_scheme)
#反向生成url(rest_framework)
u1 = request.versioning_scheme.reverse(viewname='wusir',request=request)
print(u1)
try:
ret['data'] = order
except Exception as e:
ret['msg'] = '有问题'
return JsonResponse(ret)
views.py
```
### 五、解析器
配置文件
~~~
REST_FRAMEWORK = {
"DEFAULT_PARSER_CLASSES": ['rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser']
}
~~~
视图函数中可以直接通过request.data拿到解析之后的数据
### 六、序列化
序列化共有两个功能:1、数据序列化 2、请求数据校验
数据序列化
```
from django.db import models
class UserGroup(models.Model):
title = models.CharField(max_length=32)
class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64)
group = models.ForeignKey("UserGroup")
roles = models.ManyToManyField("Role")
class UserToken(models.Model):
user = models.OneToOneField(to='UserInfo')
token = models.CharField(max_length=64)
class Role(models.Model):
title = models.CharField(max_length=32)
models.py建表
```
```
import json
from rest_framework.views import APIView
from django.http import HttpResponse
from rest_framework import serializers
from app.models import *
#=========================================
# 自定义序列化类一
class RolesSerializers(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
class RoleViews(APIView):
def get(self,request,*args,**kwargs):
# 方式一 ,没有使用数据序列化
res = Role.objects.all().values('title')
res = list(res)
res = json.dumps(res,ensure_ascii=False)
# 方式二 ,序列化多个数据[obj,obj,obj]
res = Role.objects.all()
ser = RolesSerializers(instance=res,many=True)
res = json.dumps(ser.data,ensure_ascii=False)
# 方式三 ,序列化单个数据 [obj]
res = Role.objects.all().first()
ser = RolesSerializers(instance=res,many=False)
res = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(res)
# =========================================
# +++++++++++++++++++++++++++++++++++++++++
# 自定义序列化类二
class UserInfoSerializers(serializers.Serializer):
# user_type = serializers.IntegerField()
aaaaa = serializers.IntegerField(source='user_type')
bbbbb = serializers.CharField(source='get_user_type_display')
username = serializers.CharField()
password = serializers.CharField()
gps = serializers.CharField(source='group.id')
# rls = serializers.CharField(source='roles.all') # 用这个拿到的是一个一个的对象
rls = serializers.SerializerMethodField() # 自定义显示
def get_rls(self,row):
obj_list = row.roles.all()
ret = []
for i in obj_list:
ret.append({'id':i.id,'title':i.title})
return ret
# 自定义序列化类三
class UserInfoSerializers(serializers.ModelSerializer):
bbbbb = serializers.CharField(source='get_user_type_display')
group = serializers.CharField(source='group.title')
rls = serializers.SerializerMethodField()
def get_rls(self,row):
obj_list = row.roles.all()
ret = []
for i in obj_list:
ret.append({'id':i.id,'title':i.title})
return ret
class Meta:
model = UserInfo
# fields = '__all__'
fields = ['id','username','password','bbbbb','group','rls']
# 自定义序列化类四(深度化控制)
class UserInfoSerializers(serializers.ModelSerializer):
class Meta:
model = UserInfo
# fields = '__all__'
fields = ['id','username','password','user_type','group','roles']
depth = 1
# 自定义序列化类五(Hypermedia API)
class UserInfoSerializers(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='wusir',lookup_field='group_id',lookup_url_kwarg='pk')
class Meta:
model = UserInfo
# fields = '__all__'
fields = ['id','username','password','user_type','group','roles']
class UserInfoViews(APIView):
def get(self,request,*args,**kwargs):
users = UserInfo.objects.all()
ser = UserInfoSerializers(instance=users,many=True,context={'request':request})
res = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(res)
# GroupSerializers和GroupViews配合自定义序列化类五生成Hypermedia API后,点击url可以看详情
class GroupSerializers(serializers.ModelSerializer):
class Meta:
model = UserGroup
fields = '__all__'
class GroupViews(APIView):
def get(self,request,*args,**kwargs):
pk = kwargs.get('pk')
res = UserGroup.objects.filter(id=pk).first()
ser = GroupSerializers(instance=res,many=False)
res = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(res)
# +++++++++++++++++++++++++++++++++++++++++
views.py
```
```
from django.conf.urls import url
from app.views import *
urlpatterns = [
url('role/$',RoleViews.as_view()),
url('info/$',UserInfoViews.as_view()),
url('group/(?P<pk>\d+)$',GroupViews.as_view(),name='wusir'),
]
urls.py
```
请求数据校验
```
class XXValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if not value.startswith(self.base):
message = '标题必须以 %s 为开头。' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
pass
class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(error_messages={'required': '标题不能为空'},validators=[XXValidator('wusir'),])
# required为错误时的提示信息,validators为自定义验证器,可以自定义功能,也可以不写,不写的话只能校验数据是否为空
class UserGroupView(APIView):
def post(self, request, *args, **kwargs):
ser = UserGroupSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data['title'])
else:
print(ser.errors)
return HttpResponse('提交数据')
views.py
```
~~~
from django.conf.urls import url
from app.views import *
urlpatterns = [
url('usergroup/$',UserGroupView.as_view()),
]
~~~
### 七、分页
PS:先自定义一个序列化,然后在分页程序中导入这个序列化程序,所有的原生分页需要现在settings.py中定义一下每页显示几条数据
~~~
REST_FRAMEWORK = {
"PAGE_SIZE":2,
}
~~~
A1、分页,看第n页,每页显示n条数据(原生)
```
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
class PageView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
def get(self,request,*args,**kwargs):
roles = Role.objects.all()
pg = PageNumberPagination()
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
ser = PagerSerialiser(instance=page_roles,many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data) #页面上加上上下页的url
views.py
```
A2、分页,看第n页,每页显示n条数据(自定义)
```
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
class MyPageNumberPagination(PageNumberPagination):
page_size = 3 #默认每页显示个数
page_query_param = 'page' #get传参表示第几页
page_size_query_param = 'pagesize' #get传参表示每页显示几个
max_page_size = 5 #每页最大显示个数
class PageView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
def get(self,request,*args,**kwargs):
roles = Role.objects.all()
pg = MyPageNumberPagination()
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
ser = PagerSerialiser(instance=page_roles,many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data) #页面上加上上下页的url
views.py
```
B1. 分页,在n个位置,向后查看n条数据(原生)
```
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
class PageView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
def get(self,request,*args,**kwargs):
roles = Role.objects.all()
pg = LimitOffsetPagination()
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
ser = PagerSerialiser(instance=page_roles,many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data) #页面上加上上下页的url
views.py
```
B2. 分页,在n个位置,向后查看n条数据(自定义)
```
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 #默认每页显示个数
limit_query_param = 'limit' #get传参表示每页显示个数
offset_query_param = 'offset' #get传参表示跳过几个数据显示
max_limit = 6 #每页最大显示个数
class PageView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
def get(self,request,*args,**kwargs):
roles = Role.objects.all()
pg = MyLimitOffsetPagination()
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
ser = PagerSerialiser(instance=page_roles,many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data) #页面上加上上下页的url
views.py
```
C1.加密分页,上一页和下一页(原生)
```
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import CursorPagination
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
class PageView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
def get(self,request,*args,**kwargs):
roles = Role.objects.all()
pg = CursorPagination()
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
ser = PagerSerialiser(instance=page_roles,many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data) #页面上加上上下页的url
views.py
```
C2.加密分页,上一页和下一页(自定义)
```
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import CursorPagination
from rest_framework.views import APIView
from app.models import *
import hashlib
import time
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
class MyCursorPagination(CursorPagination):
cursor_query_param = 'wusir' #get参数中确定以什么值为key来接受下一页的参数
page_size = 3 #默认每页显示数目
ordering = 'id' #根据什么字段来进行排序
page_size_query_param = 'pagesize' #get传参表示每页显示几个
max_page_size = 5 #每页最大显示数目
class PageView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
def get(self,request,*args,**kwargs):
roles = Role.objects.all()
pg = MyCursorPagination()
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
ser = PagerSerialiser(instance=page_roles,many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data) #页面上加上上下页的url
views.py
```
### 八、视图
PS:View和APIView在此处就不多介绍
GenericAPIView
```
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from app.models import *
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
class View1View(GenericAPIView):
authentication_classes = []
permission_classes = []
throttle_classes = []
queryset = Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
def get(self,request,*args,**kwargs):
# 获取数据
roles = self.get_queryset()
# 分页
pager_roles = self.paginate_queryset(roles)
# 序列化
ser = self.get_serializer(instance=pager_roles,many=True)
return Response(ser.data)
views.py
```
GenericViewSet(as\_view里面可以用字典的方式让get,post等不同的方法对应执行不同名称的函数)
```
from rest_framework.pagination import PageNumberPagination
from app.models import *
from rest_framework.response import Response
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import GenericViewSet
class View1View(GenericViewSet):
authentication_classes = []
permission_classes = []
throttle_classes = []
queryset = Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
def list(self, request, *args, **kwargs):
# 获取数据
roles = self.get_queryset()
# 分页
pager_roles = self.paginate_queryset(roles)
# 序列化
ser = self.get_serializer(instance=pager_roles, many=True)
return Response(ser.data)
views.py
```
~~~
from django.conf.urls import url
from app.views import *
urlpatterns = [
url(r'^view1view/$',View1View.as_view({'get':'list'})),
]
~~~
mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,
(任意举两个栗子)
```
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import GenericViewSet,ModelViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class View1View(GenericViewSet,ListModelMixin,CreateModelMixin):
authentication_classes = []
permission_classes = []
throttle_classes = []
queryset = Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
views.py
```
~~~
from django.conf.urls import url
from app.views import *
urlpatterns = [
url(r'^view1view/$',View1View.as_view({'get':'list','post':'create'})),
]
~~~
ModelViewSet
```
from app.rest_utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import ModelViewSet
class View1View(ModelViewSet):
authentication_classes = []
permission_classes = []
throttle_classes = []
queryset = Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
views.py
```
```
from django.conf.urls import url
from app.views import *
urlpatterns = [
url(r'^view1view/$',View1View.as_view({'get': 'list','post':'create'})),
url(r'^view1view/(?P<pk>\d+)/$',View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
]
urls.py
```
继承关系:APIView继承了View,GenericAPIView继承了APIView,GenericViewSet继承了GenericAPIView和ViewSetMixin,ModelViewSet继承了mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin和GenericViewSet。
### 九、路由系统
当继承了ModelViewSet之后,一个视图对于的完整的路由就有以下四种
```
from django.conf.urls import url
from app.views import *
urlpatterns = [
# http://127.0.0.1:8000/api/v1/v1/?format=json
url(r'^(?P<version>[v1|v2]+)/view1view/$', View1View.as_view({'get': 'list','post':'create'})),
# http://127.0.0.1:8000/api/v1/v1.json
url(r'^(?P<version>[v1|v2]+)/view1view\.(?P<format>\w+)$', View1View.as_view({'get': 'list','post':'create'})),
url(r'^(?P<version>[v1|v2]+)/view1view/(?P<pk>\d+)/$', View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
url(r'^(?P<version>[v1|v2]+)/view1view/(?P<pk>\d+)\.(?P<format>\w+)$', View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
]
urls.py
```
这时候我们可以使用rest\_framework给我们自动生成路由的方式来生成以上四种路由,效果相同
```
from django.conf.urls import url, include
from app.views import *
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'view1view',View1View)
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
]
urls.py
```
### 十、渲染器
只需要在配置文件中配置一下所需要的渲染器类型就可以了
~~~
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES":[
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
]
}
~~~
- Python学习
- Python基础
- Python初识
- 列表生成式,生成器,可迭代对象,迭代器详解
- Python面向对象
- Python中的单例模式
- Python变量作用域、LEGB、闭包
- Python异常处理
- Python操作正则
- Python中的赋值与深浅拷贝
- Python自定义CLI三方库
- Python并发编程
- Python之进程
- Python之线程
- Python之协程
- Python并发编程与IO模型
- Python网络编程
- Python之socket网络编程
- Django学习
- 反向解析
- Cookie和Session操作
- 文件上传
- 缓存的配置和使用
- 信号
- FBV&&CBV&&中间件
- Django补充
- 用户认证
- 分页
- 自定义搜索组件
- Celery
- 搭建sentry平台监控
- DRF学习
- drf概述
- Flask学习
- 项目拆分
- 三方模块使用
- 爬虫学习
- Http和Https区别
- 请求相关库
- 解析相关库
- 常见面试题
- 面试题
- 面试题解析
- 网络原理
- 计算机网络知识简单介绍
- 详解TCP三次握手、四次挥手及11种状态
- 消息队列和数据库
- 消息队列之RabbitMQ
- 数据库之Redis
- 数据库之初识MySQL
- 数据库之MySQL进阶
- 数据库之MySQL补充
- 数据库之Python操作MySQL
- Kafka常用命令
- Linux学习
- Linux基础命令
- Git
- Git介绍
- Git基本配置及理论
- Git常用命令
- Docker
- Docker基本使用
- Docker常用命令
- Docker容器数据卷
- Dockerfile
- Docker网络原理
- docker-compose
- Docker Swarm
- HTML
- CSS
- JS
- VUE