文章目录
分页
1. PageNumberPagination
- 局部分页
# setting.py
# drf相关配置
REST_FRAMEWORK = {
"PAGE_SIZE": 2,
}
# views.py
from rest_framework.pagination import PageNumberPagination
class UserView(ListCreateAPIView):
# 分页
pagination_class = PageNumberPagination
- 全局分页
# drf相关配置
REST_FRAMEWORK = {
"PAGE_SIZE": 2,
'DEFAULT_PAGINATION_CLASS': "rest_framework.pagination.PageNumberPagination",
}
- 效果
{
"count": 6,
"next": "http://127.0.0.1:8000/user/?page=3",
"previous": "http://127.0.0.1:8000/user/",
"results": [
{
"url": "http://127.0.0.1:8000/user/10",
"username": "233214",
"password": "666888",
"gender": "1",
"tel": "123456789"
},
{
"url": "http://127.0.0.1:8000/user/12",
"username": "233214古典风格",
"password": "666888",
"gender": "1",
"tel": "123456789"
}
]
}
2. LimitOffsetPagination
- 设置
from rest_framework.pagination import LimitOffsetPagination
pagination_class = LimitOffsetPagination
- 效果
{
"count": 6,
"next": "http://127.0.0.1:8000/user/?limit=2&offset=4",
"previous": "http://127.0.0.1:8000/user/?limit=2",
"results": [
{
"url": "http://127.0.0.1:8000/user/10",
"username": "233214",
"password": "666888",
"gender": "1",
"tel": "123456789"
},
{
"url": "http://127.0.0.1:8000/user/12",
"username": "233214古典风格",
"password": "666888",
"gender": "1",
"tel": "123456789"
}
]
}
3. CursorPagination
from rest_framework.pagination import CursorPagination
pagination_class = CursorPagination
此时报错:
Cannot resolve keyword 'created' into field. Choices are: address, gender, id, password, tel, username
原因是内置分页类中默认按照‘created’字段排序,但自己写的User类中没有该字段。
解决:编写新类继承原类,重写ordeing的值
# user\paginations.py
from rest_framework.pagination import CursorPagination
# 按照tel字段排序的分页器
class TelCuroserPagination(CursorPagination):
ordering = '-tel'
# views.py
from user.paginations import *
class UserView(ListCreateAPIView):
pagination_class = TelCursorPagination
- 效果
页面显示previous/next按钮
{
"next": "http://127.0.0.1:8000/user/?cursor=cD02Nzg5",
"previous": "http://127.0.0.1:8000/user/?cursor=bz0xJnI9MSZwPTY3ODk%3D",
"results": [
{
"url": "http://127.0.0.1:8000/user/1",
"username": "wsm",
"password": "666888",
"gender": "0",
"tel": "123456789"
},
{
"url": "http://127.0.0.1:8000/user/12",
"username": "233214古典风格",
"password": "666888",
"gender": "1",
"tel": "6789"
}
]
}
4. 在自定义函数中用drf分页器实现分页
# user\paginations.py
from rest_framework.pagination import CursorPagination
# 按照tel字段排序的分页器
class TelCuroserPagination(CursorPagination):
ordering = '-tel'
# views.py
class UserView(ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
# 分页
pagination_class = TelCursorPagination
def list(self, request, *args, **kwargs):
paginator = self.pagination_class()
page = paginator.paginate_queryset(self.queryset, request)
serializer = self.serializer_class(page, many=True, context={"request": request})
return paginator.get_paginated_response(serializer.data)
权限管理
- AllowAny
- IsAuthenticated
- IsAdminUser
- IsAuthenticatedOrReadOnly
from rest_framework.permissions import IsAuthenticated
class UserView(ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
# 分页
pagination_class = TelCursorPagination
# 权限
permission_classes = [IsAuthenticated]
DRF授权管理
默认采用session登录授权。
创建超级用户python manage.py createsuperuser
,登录
如果报错Table 'xxx.auth_user' doesn't exist
,执行迁移的两个步骤。
JWT(JSON WEB Token)授权管理
- 安装
pip install djangorestframework_simplejwt
- 配置
# drf相关配置
REST_FRAMEWORK = {
# 分页
"PAGE_SIZE": 5,
'DEFAULT_PAGINATION_CLASS': "rest_framework.pagination.PageNumberPagination",
# 权限
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
- 设置路由
添加api/token/
和api/token/refresh/
两个路由
参考来源:https://github.com/davesque/django-rest-framework-simplejwt
# 项目路由urls.py
from django.conf.urls import url
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
……
# jwt授权管理
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
- 发送请求
用户名和密码通过python manage.py createsuperuser
创建。
获得两个值:
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU3NjA1OTU5NSwianRpIjoiNmY5ZmU3ZGI1ZWNjNDkxN2E3MWRkZWFkYmM3MzkyNjAiLCJ1c2VyX2lkIjoxfQ.nRADSnDHXgQ7wf3g0cSiIF8RZZhUBDCw_omFXUek4nY",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTc1OTczNDk1LCJqdGkiOiI1Y2VhNjc4N2M3M2Y0NjIzOTA2NWY4MThlNmZjZTFmMyIsInVzZXJfaWQiOjF9.ELaRHVD9dswHNqzkPieO0v8nargj6uBORBFRjRtqCUk"
}
- token的使用:
在Authorization中选择Bearer Token,填入token
实际上相当于在header中填入Authorization键值: - refresh的使用
在表单中填入refresh值
过滤
1. django_filters.rest_framework.DjangoFilterBackend
支持REST框架的高度可定制的字段过滤
- 配置
- 添加INSTALL_APPS:
# setting.py
INSTALLED_APPS=[
……
'django_filters'
]
- 如果是全局配置:
# setting.py
# drf相关配置
REST_FRAMEWORK = {
……
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
- 如果是局部配置:
在视图类中添加filter_backends = [DjangoFilterBackend]
- 在视图类中添加
filterset_fields = ['过滤字段', ……]
# views.py
class UserView(ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
# 过滤
filterset_fields = ['username', 'tel']
- 效果
精确匹配。查找用户名为‘wsm’只能查到‘wsm’,查不到‘wsm123’. - 在自定义函数中不生效,解决:
自定义函数中对queryset进行过滤queryset = self.filter_queryset(self.queryset)
class UserView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 分页
pagination_class = TelCursorPagination
# 权限
# permission_classes = [IsAuthenticated]
# 过滤
filterset_fields = ['username']
def list(self, request, *args, **kwargs):
# 过滤器
queryset = self.filter_queryset(self.queryset)
# 分页
page = self.paginate_queryset(queryset)
# 序列化
serializer = self.serializer_class(page, many=True, context={"request": request})
return self.get_paginated_response(serializer.data)
2. rest_framework.filter.SearchFilter
- 配置
from rest_framework.filters import SearchFilter
class UserView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 分页
pagination_class = TelCursorPagination
# 权限
# permission_classes = [IsAuthenticated]
# 过滤1
filterset_fields = ['username', 'tel']
# 过滤2
filter_backends = [SearchFilter]
search_fields = ['username', 'tel']
- 效果
模糊查询。 - 高级检索
搜索行为可以通过在其中添加各种字符来限制search_fields。
①^
开始 - 搜索。
②=
完全匹配。
③@
全文搜索。(目前只支持Django的MySQL后端。)
④$
正则表达式搜索。
例如,search_fields = ["^username", "$password"]
3. OrderingFilter
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [filters.OrderingFilter]
ordering_fields = ['username', 'email']
ordering = ['username']
4. 自定义
继承BaseFilterBackend,
并覆盖该.filter_queryset(self, request, queryset, view)方法。
该方法应返回一个新的过滤查询集。
class IsOwnerFilterBackend(filters.BaseFilterBackend):
"""
Filter that only allows users to see their own objects.
"""
def filter_queryset(self, request, queryset, view):
return queryset.filter(owner=request.user)
跨域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户信息</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
</head>
<body>
<script>
$.ajax({
url: 'http://127.0.0.1:8000/user/',
method: 'get',
dataType: 'json',
success: function (data) {
console.log(data)
}
})
</script>
</body>
</html>
调用不同协议/不同域名/不同端口报错:
cors:1 Access to XMLHttpRequest at 'http://127.0.0.1:8000/user/' from origin 'http://127.0.0.1:9000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
jquery-3.2.1.min.js:4 Cross-Origin Read Blocking (CORB) blocked cross-origin response http://127.0.0.1:8000/user/ with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.
这就是跨域问题。
1. script跨域
参考来源:https://github.com/axios/axios
# 在8000端口转为json
class UserView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin,
GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def list(self, request, *args, **kwargs):
# 过滤器
queryset = self.filter_queryset(self.queryset)
#
data = queryset
serializer = self.serializer_class(data, many=True, context={"request": request})
text = json.dumps(serializer.data)
text = json.loads(text)
text = f"test({text})"
response = HttpResponse(text)
response["Content-Type"] = 'application/javascript'
return response
# 9000调用8000端口的页面定义一个test函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户信息</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="cors"></div>
<a href="#" onclick="show_user()">查看用户</a>
<script>
{#$.ajax({#}
{# url: 'http://127.0.0.1:8000/user/',#}
{# method: 'get',#}
{# dataType: 'json',#}
{##}
{# success: function (data) {#}
{# console.log(data)#}
{# }})#}
function show_user() {
let script = "<script src='http://127.0.0.1:8000/user/'>" + "</" + "script>"
console.log(script)
$("#cors").html(script)
}
function test(data) {
console.log(data)
}
</script>
</body>
</html>
2. jsonp跨域
原理是script标签,jsonp的在使用的时候、要求后端必须支持,后端返回的不是一个标准的JSON,而是一个形似 javascript 函数的表示形式 。
设置dataType: 'jsonp',
和sonpCallback: 'test',
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户信息</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="cors"></div>
<a href="#" onclick="show_user()">查看用户</a>
<script>
function show_user() {
$.ajax({
url: 'http://127.0.0.1:8000/user/',
method: 'get',
dataType: 'jsonp',
jsonpCallback: 'test',
success: function (data) {
console.log(data)
}
})
}
function test(data) {
console.log(data)
}
</script>
</body>
</html>
3. cors
Cross-Origin Resource Sharing(跨站资源共享)策略,来实现 跨域
原理:主要在 后端服务器上、在响应的头信息上,添加一个
Access-Control-Allow-Origin = * 这样的头信息即可
DRF 是通过 django-cors-headers 来解决跨域的问题。
在 DRF 中引入 django-cors-headers的步骤如下:
- 安装:
pip install django-cors-headers
- 配置setting.py
INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user',
'good',
'rest_framework',
'django_filters',
'corsheaders',
]
MIDDLEWARE
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
配置跨域属性
# 设置跨域的白名单
CORS_ORIGIN_WHITELIST = [
'http://www.baidu.com',
'http://www.sina.com',
]
CORS_ORIGIN_ALLOW_ALL = False
# 如果设置为True, 白名单失效, 则允许所有的网站都可以跨域访问
CORS 除了在响应的头信息上设置 Access-Control-Allow-Origin 来允许某个资源进行跨域
还可以通过 反向代理 的技术 进行跨域
在反向代理的时候,需要在代理服务器上设置 Access-Control-Allow-Origin