Django--restframework
Django--restframework
一 . rest framework框架的认识
-
它是基于Django的,帮助我们快速开发符合RESTful规范的接口框架
-
安装 pip
二 . 什么是RESTful风格
三 . 基于Django实现
urls.py
urlpatterns = [
path('index/', views.TestView.as_view()), # 函数视图
]
views.py
from django.forms import model_to_dict
from django.http import HttpResponse, JsonResponse
from django.views import View
class TestView(View):
def get(self, request):
data = request.GET.get('name') # View获取前端传递的GET请求name参数
return HttpResponse(data)
def post(self, request):
data = request.POST.get('username') # View获取前端传递的POST请求username参数
return HttpResponse(data)
class TestView(View):
#基于django的序列化 for循环
def get(self, request):
queryset = User.objects.all()
print(queryset)
list = []
for i in queryset:
list.append(model_to_dict(i)) # model对象转换成dict
# list.append({
# "name": i.name,
# "age": i.age,
# "home": i.home
# })
print(list)
# In order to allow non-dict objects to be serialized set the safe parameter to False.
# return JsonResponse(list)——》一定要加上:safe=False
return JsonResponse(list, safe=False)
四 . 基于Django Rest Framework框架实现
DRF框架之视图集APIView:https://www.cnblogs.com/tjw-bk/p/13886536.html
models.py
from django.db import models
# 角色表
class Role(models.Model):
role_name = models.CharField(max_length=32, verbose_name='角色')
class Meta:
db_table = 'tb_role'
verbose_name = '角色'
verbose_name_plural = verbose_name
#用户表
class User(models.Model):
name = models.CharField(max_length=12, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
home = models.CharField(max_length=255, null=True, verbose_name='家乡')
role = models.ManyToManyField(Role)
class_room = models.ForeignKey(to='ClassRoom', on_delete=models.CASCADE, null=True)
class Meta:
db_table = 'tb_user'
verbose_name = '用户'
verbose_name_plural = verbose_name
#班级表
class ClassRoom(models.Model):
classroom = models.CharField(max_length=20, verbose_name='班级')
address = models.CharField(max_length=32, verbose_name='地址')
class Meta:
db_table = 'tb_clasroom'
verbose_name = '班级'
verbose_name_plural = verbose_name
urls.py
# 子路由文件
from django.urls import include, path
from user import views
from rest_framework.routers import SimpleRouter, DefaultRouter
# 自动生成路由方法,必须使用视图集
# router=SimpleRouter() #没有根路由 /user/无法识别 生产环境使用
router = DefaultRouter() # 有根路由 # 开发环境用,有主界面
router.register(r'user2', views.UserModelViewSet) # 配置路由
urlpatterns = [
path('user/', views.UserView.as_view()),
path('',include(router.urls))
]
自定义序列化页面serializers.py
from rest_framework import serializers
from .models import *
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
depth = 1 # 外键序列化
1. 分页
1.1 PageNumberPagination
前端访问网址形式:
GET http://192.168.56.100:8888/user/user2?page=1
可以在子类中定义的属性:
- page_size_query_param = 'page_size' 前端发送的每页数目关键字名,默认为None
- max_page_size = 4 前端最多能设置的每页数量
- page_size = 2 每页数目
- page_query_param = 'page' 前端发送的页数关键字名,默认为"page"
1.2 可在setting配置全局分页器
-
INSTALLED_APPS = [ 'rest_framework', #需要注册应用 ]
-
REST_FRAMEWORK = { # 分页(全局):全局分页器, 例如 省市区的数据自定义分页器, 不需要分页 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # 每页返回数量 'PAGE_SIZE': 10, # 默认 None }
1.3 views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination #导包
#自定义分页类
class PageNumberPagination2(PageNumberPagination):
page_size_query_param = 'page_size'
max_page_size = 4
page_size = 2
page_query_param = 'page'
'''
手写分页
def get(self, request):
# 手写页面器
num = request.GET.get('num', 1)
num = int(num)
queryset = Goods.objects.all()
paginator = Paginator(queryset, 1)
onepage = paginator.get_page(num)
resp = {}
resp['data'] = GoodsSer(onepage, many=True).data
resp['next_page'] = num + 1
resp['prev_page'] = num - 1
resp['page_range'] = [i for i in paginator.page_range]
return Response(resp)
'''
class UserModelViewSet(ModelViewSet):
#设置查询集
queryset = User.objects.all()
#设置序列化器类
serializer_class = UserSerializers
#设置分页器
pagination_class = PageNumberPagination2 #使用自定义分页器
#pagination_class = PageNumberPagination #使用全局分页器
#http://192.168.56.100:8888/user/user2?page=2
1.4 使用postman测试
2.排序
- 对于列表数据 rest framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照字段进行排序。
2.1 在setting.py中配置全局排序
-
INSTALLED_APPS = [ 'rest_framework', #需要注册应用 ]
-
REST_FRAMEWORK = { #过滤排序(全局):Filtering 过滤排序 'SEARCH_PARAM': 'search', 'ORDERING_PARAM': 'ordering', 'NUM_PROXIES': None, }
2.2 使用方法:
在类视图中设置filter_backends,使用from rest_framework.filters import OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集合进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
示例:
views.py
from rest_framework.viewsets import ModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
class UserModelViewSet(ModelViewSet):
# queryset = User.objects.all().order_by('id')
queryset = User.objects.all()
serializer_class = UserSerializers
pagination_class = PageNumberPagination
filter_backends = [OrderingFilter,]
# 排序
ordering_fields = ('id', 'age', 'class_room') #需要排序的字段
#http://192.168.56.100:8888/user/user2?ordering=-age 使用age字段从大到小排序
#http://192.168.56.100:8888/user/user2?ordering=age 使用age字段从小到大排序
2.3 使用postman测试
3.过滤
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django_filters扩展来增强支持。
pip install django_filters
3.1 在setting.py中配置
-
INSTALLED_APPS = [ 'django_filters', 'rest_framework', ]
-
REST_FRAMEWORK = { # 过滤器后端 'DEFAULT_FILTER_BACKENDS': [ 'django_filters.rest_framework.DjangoFilterBackend', # 'django_filters.rest_framework.backends.DjangoFilterBackend', 包路径有变化 ], }
3.2 views.py
from rest_framework.viewsets import ModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
class UserModelViewSet(ModelViewSet):
# queryset = User.objects.all().order_by('id')
queryset = User.objects.all()
serializer_class = UserSerializers
pagination_class = PageNumberPagination
# 过滤
filter_backends = [OrderingFilter, DjangoFilterBackend]
filter_fields = ('name', 'age') #参加过滤的字段
#http://192.168.56.100:8888/user/user2?name=马六
3.3 使用postman测试
4.限流 Throttling
可以对接口访问的频次进行限制,以减轻对服务器的压力
4.1 在setting.py中配置
-
INSTALLED_APPS = [ 'rest_framework', ]
-
REST_FRAMEWORK = { # 3.限流(防爬虫) 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle', ], # 3.1限流策略 'DEFAULT_THROTTLE_RATES': { 'user': '1/hour', # 认证用户每小时100次 'anon': '3/day', # 未认证用户每天能访问3次 }, 'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation', 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata', 'DEFAULT_VERSIONING_CLASS': None, }
DEFAULT_THROTTLE_RATES 可以使用 second,minute,hour或day来指明周期。
4.2 views.py
from rest_framework.throttling import AnonRateThrottle,UserRateThrottle
from rest_framework.viewsets import ModelViewSet
class UserModelViewSet(ModelViewSet):
# queryset = User.objects.all().order_by('id')
queryset = User.objects.all()
serializer_class = UserSerializers
#限流自定义限流类
throttle_classes = [AnonRateThrottle]
#超出限定的次数会报错
# "detail": "Request was throttled. Expected available in 86398 seconds."
4.3 使用postman测试
5. 序列化
详情看我之前的博客:https://www.cnblogs.com/tjw-bk/p/13805532.html
6.认证
认证即需要知道是谁在访问服务器,需要有一个合法身份。认证的方式可以有很多种,例如session+cookie、token等,这里以token为例。如果请求中没有token,我们认为这是未登录状态,有些接口要求必须登录才能访问,如果未登录,我们可以一些处理(比如重定向登录页、返回错误信息等)
- 局部认证:
url.py
from django.conf.urls import url, include
from DemoApp.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
功能代码:utils/auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed,ValidationError
from DemoApp.models import User
class MyAuth(BaseAuthentication):
def authenticate(self, request):
"认证逻辑"
# 做认证,判断是否登陆。首先拿到token,在数据库里去判断
token = request.query_params.get("token","")
if not token:
raise AuthenticationFailed("没有token")
try:
user = User.objects.filter(token=token).first()
if not user:
pass
raise AuthenticationFailed("无效的token")
except Exception as e:
msg = "无效的token" if hasattr(e, "messages") else "非法的token"
raise AuthenticationFailed(msg)
return (user, token) # 返回值是一个元素,分别对应视图中request的user,auth
views.py
class TestView(APIView):
authentication_classes = [MyAuth, ] # 局部认证
def get(self, request, *args, **kwargs):
"通过认证后进入views类进行业务处理"
print(request.user)
print(request.auth)
pass
在上述代码中,实现了TestView视图类的认证功能。如果认证成功,向视图类中的request对象中返回requset.user和request.auth;如果认证失败,触发异常,不会进入视图处理,直接返回前端认证失败的结果。在实际的业务中这样并不合适,我们可以将其替代成重定向操作。
- 全局认证
- 将视图类中的authentication_classes属性删除
- settings.py配置文件中 RESTFRAMEWORK 添加配置
6.1 在setting.py中配置
-
INSTALLED_APPS = [ 'rest_framework', ]
-
REST_FRAMEWORK = { # 1.认证器(全局) 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 在DRF中配置JWT认证 'rest_framework.authentication.SessionAuthentication', # 使用session时的认证器 'rest_framework.authentication.BasicAuthentication' # 提交表单时的认证器 ], }
如果在全局认证下,有些接口不想加上认证,可以在这个类的属性 authentication_classes = [ ] 即可。
除了上述自己实现的认证类,REST Framework为我们了四种认证类:(直接在视图类中使用即可)
from rest_framework.authentication import BaseAuthentication,SessionAuthentication ......
1.BasicAuthentication 基于用户名密码
2.SessionAuthentication 基于session
3.TokenAuthentication 基于token,与示例中类似
4.RemoteUserAuthentication
6.2 views.py
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class CourseViewSet(viewsets.ModelViewSet):
# 1.认证:自定义认证类,自定义会覆盖全局配置
authentication_classes = (BasicAuthentication, SessionAuthentication, JSONWebTokenAuthentication)
7.权限
根据不同权限用户对于api的访问频次,其他限制等等
7.1 在setting.py中配置
-
INSTALLED_APPS = [ 'rest_framework', ]
-
REST_FRAMEWORK = { # 2.权限配置(全局): 顺序靠上的严格 'DEFAULT_PERMISSION_CLASSES': [ # 'rest_framework.permissions.IsAdminUser', # 管理员可以访问 'rest_framework.permissions.IsAuthenticated', # 认证用户可以访问 # 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 认证用户可以访问, 否则只能读取 'rest_framework.permissions.AllowAny', # 所有用户都可以访问 ], }
7.2 views.py
from rest_framework.permissions import AllowAny, IsAuthenticated
class CourseTagViewSet(viewsets.ModelViewSet):
queryset = CourseTag.objects.all()
serializer_class = CourseTagSer
# 2.权限:自定义权限类
# permission_classes = (AllowAny,)
permission_classes = (IsAuthenticated,)
7.3 使用postman测试
8.版本
参考博客:https://openapi.alipay.com/gateway.do?
https://www.jb51.net/article/166249.htm