refrem权限组件 和认证组件 解析器,分页,路由
知识点:
#获取用户的ip地址
#visit_ip=request.META.get('REMOTE_ADDR')
restfromwork 客户端发送post,等ajax请求的时候不用发送csrf信息
是因为在源码中,对as_view()方法进行了设置,使他不进行csrf验证
![]()
认证与权限组件
在使用这些组件之前要先写好模板
认证的功能:
将请求中的数据进行验证然后查看当前用户的信息
并经信息返回,可以在视图类中调用,也可以在权限组件中调用认证之后的信息
如用户登陆之后找到当前的用户信息
认证类中就可以返回两个信息回来
调用方式 request.user request.auth 这两种方式都可以调用

class User(models.Model): user=models.CharField(max_length=32) pwd=models.CharField(max_length=32) #此字段时用于权限组件中来判断用户权限级别, #从而确定用户拥有那些权限 user_type=models.IntegerField(choices=((1,"普通用户"),(2,"VIP"),(3,"SVIP")),default=1) #此组件是用于判断认证组件的,并一对一关联到用户表 #当用户登录时登录试图会给url加上一个token 字段 #通过取出这个值来判断是否已登陆 详见认证组件的原理和登录视图 class UserToken(models.Model): user=models.OneToOneField("User") token=models.CharField(max_length=128)
认证组件
局部视图认证
这里注意认证组件执行的位置是在APIView执行到dispatch()的时候执行的
中间件的认证比dispatch() 早
在app01.service.auth.py:
#encoding=utf-8 from rest_framework import exceptions #引入报错组件,当出现错误时报这个错 from ..models import * from rest_framework.authentication import BaseAuthentication #这里继承了BaseAuthentication 它里边有两个方法 # def authenticate 和 def authenticate_header # 这里因为我只用到了一种authenticate方法 所以另外一个我不用写, #直接继承即可 class MyAuthentication(BaseAuthentication): def authenticate(self, request): #在get请求头中取出‘token’ 因为此时的request已经被重新封装了 #原来的request被封装在request._request 所以用他来调用GET中的内容 token=request._request.GET.get('token') user_token_obj=UserToken.objects.filter(token=token).first() if user_token_obj: #当验证成功时,返回两个数据 return user_token_obj.user,token else: #失败是抛出错误 raise exceptions.AuthenticationFailed('验证失败')
在views.py:
定义一个登录视图类
定义一个给图书模板序列化的类
#定义一个给图书模板序列化的类 class BookSerializersModel(serializers.ModelSerializer): #显示出来外键关联的内容的查看连接 publish=serializers.HyperlinkedIdentityField( view_name='publish_detail', lookup_field='publish_id', lookup_url_kwarg="pk" ) class Meta: model=Book fields='__all__' #自定义个别字段的显示内容 authors = serializers.SerializerMethodField() def get_authors(self, obj): temp = [] for authors in obj.authors.all(): temp.append({'name': authors.name}) return temp
定义一个BookView类
from api.service.auth import * class BookView(ModelViewSet): #给这个视图单独定义验证组件,authentication_classes #在APIView中会直接调用用户自己定义的authentication_classes authentication_classes = [MyAuthentication]
#这里的authentication_classes的名字是固定的
permission_classes=[] #这两个内容必须要写上,在源码中会使用这些内容 #传入queryset queryset = Book.objects.all() #传入一个自定义序列化图书模板的类,在源码中会调用self.serializer 会调用这个 serializer_class=BookSerializersModel
全局视图认证组件
settings.py配置如下:
|
1
2
3
|
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]}#列表中写的内容是自定义验证组件的路径
|
权限组件
局部视图权限
在app01.service.permissions.py中:
在views.py:
from api.service.auth import * from api.service.permission import * class BookView(ModelViewSet): #给这个视图单独定义验证组件,authentication_classes #在APIView中会直接调用用户自己定义的authentication_classes authentication_classes = [MyAuthentication] #权限组件是在认证组件的基础上的 因为权限组件 #用到了认证组件中的内容request.user permission_classes=[SVIPPermisson] #这两个内容必须要写上,在源码中会使用这些内容 #传入queryset queryset = Book.objects.all() #传入一个自定义序列化图书模板的类 serializer_class=BookSerializersModel
全局视图权限
settings.py配置如下:
|
1
2
3
4
|
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]} |
throttle(访问频率)组件
局部视图throttle
在app01.service.throttles.py中:
在views.py中:
from app01.service.throttles import *
class BookViewSet(generics.ListCreateAPIView):
throttle_classes = [VisitThrottle,]
queryset = Book.objects.all()
serializer_class = BookSerializers
全局视图throttle
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
#前边的名字是固定的 后边的内容是自定义的类的路径
"DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}
内置throttle类
在app01.service.throttles.py修改为:
class VisitThrottle(SimpleRateThrottle):
scope="visit_rate"
def get_cache_key(self, request, view):
return self.get_ident(request)
settings.py设置:
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
"DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
"DEFAULT_THROTTLE_RATES":{
"visit_rate":"5/m", #这里注意 m=60 h=60*60 以此类推 前后两个值都可以进行设置
}
}
解析器
request类
django的request类和rest-framework的request类的源码解析 所有请求过来的数据都放在了request.data中


所以这里注意 当传送的数据是j'son 的类型时,不能够使用request.data.get_list('k1')的方法去得到数据,
因为只有数据时QueryDict的类型的数据才有此方法
在postman中提交json数据的提交方式



在postman中提交urlencod数据的提交方式

因为没有给他设置解析器,然后使用默认的解析器,默认解析器有着三种

自定义解析器

如何改变返回给网页中渲染出的页面


局部视图
from rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
parser_classes = [FormParser,JSONParser]
queryset = Publish.objects.all()
serializer_class = PublshSerializers
def post(self, request, *args, **kwargs):
print("request.data",request.data)
return self.create(request, *args, **kwargs)
全局视图
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
"DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
"DEFAULT_THROTTLE_RATES":{
"visit_rate":"5/m",
},
"DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
}
路由
没有引入路由的时候定义url 的写法
注意 :继承了GenericViewSet,或者Modelviewset 的视图类 在写url的时候,都要在url 中的 as_view()中加入对应关系
都要定义一个queryset,否则就会报错,找不到这个内容
![]()
1. django rest framework - 路由: API: 列表: ^/api/(?P<version>[v1|v2]+)/course/$ CourseView.as_view() 示例: /api/v1/course/ ^/api/(?P<version>[v1|v2]+)/course\.(?P<format>\w+)$ CourseView.as_view() 示例: /api/v1/course.json 在后端配置好对应返回的数据就可以,.json就在后端定义给用户返回json形式的文件 详细: ^/api/(?P<version>[v1|v2]+)/course/(?P<pk>\d+)/$ CourseView.as_view() 示例: /api/v1/course/1/ v1表示版本 依据版本来访问 这个一般网站都有的 ^/api/(?P<version>[v1|v2]+)/course/(?P<pk>\d+)\.(?P<format>\w+)$ CourseView.as_view() 示例: /api/v1/course/1.json - 视图: 第一类: 此类视图是继承了view 需要用户自己去定义视图类中的 get post delete updata等方法
但是需要用户
至少写两个视图类,一个来处理不带pk 的 如 list post 一个来处理带pk的 如显示单个数据, 删除 修改
View APIView(View) GenericAPIView(views.APIView) 注意:
路由: ^/api/(?P<version>[v1|v2]+)/course/$ CourseView.as_view(), 自动触发get/post/delete等方法 注意as_view()中没有数据 第二类: 他继承了mixin中的类 这些类中定义了对应的方法 如DestroyModelMixin中定了distroy方法
需要把delete:dstroy对应关系写到as_view中去 GenericViewSet(ViewSetMixin, generics.GenericAPIView) ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet ) 注意: 路由: ^/api/(?P<version>[v1|v2]+)/course/$ CourseView.as_view({'get':'list','post':"creat",}), 自动触发get/post/delete等方法
在继承了Modelviewset类的试图函数中的url 要写成如下形式 以区分有没有PK键
我们的视图到底应该继承哪个类? a. 简单的接口,返回的数据比较简单没有跨表查询什么的就,继承 ModelViewSet 或者mixin中的类 PS: 继承 class XXView(mixins.ListModelMixin,GenericViewSet) b. 复杂接口如有外键,部分内容不现实,部分内容显示什么,这种就要自己去写get list等方法: - APIView(View) - GenericAPIView(views.APIView)
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r"books\.(?P<format>\w+)$",views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"), url(r"books/$",views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"), url(r"books/(?P<pk>\d+)/$",views.BookViewSet.as_view({"get":"retrieve","delete":"destroy","put":"update"}),name="book_detail"), url(r"books/(?P<pk>\d+)\.(?P<format>\w+)$",views.BookViewSet.as_view({"get":"retrieve","delete":"destroy","put":"update"}),name="book_detail"), ]

路由模块的用法
from django.conf.urls import url,include from django.contrib import admin from api import views #引入路由模块 from rest_framework import routers #实例话一个路由对象 router = routers.DefaultRouter() #将试图类注册到路由中 router.register(r'books', views.BookViewSet) urlpatterns = [ url(r'^admin/', admin.site.urls), #使用路由 url(r'^', include(router.urls)),
]

分页
一 直接使用原生分页类


注意使用原生类的时候一定要去setting中设置PAGE_SIZE

简单分页
2 自定义一个分页类
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class PNPagination(PageNumberPagination): page_size = 1 #限定每页显示多少条数据 page_query_param = 'page'
#这个配置决定在这儿输入“内容”=“页码” 跳转到相应的页面
page_size_query_param = "size"
max_page_size = 5 #限制每页最多能显示多少条数据
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializers
def list(self,request,*args,**kwargs):
book_list=Book.objects.all()
pp=LimitOffsetPagination()
pager_books=pp.paginate_queryset(queryset=book_list,request=request,view=self)
print(pager_books)
bs=BookSerializers(pager_books,many=True)
#return Response(bs.data)
return pp.get_paginated_response(bs.data)
自定义的分页器

偏移分页
定义方式
from rest_framework.pagination import LimitOffsetPagination class MyPageNumberPagination(LimitOffsetPagination):pass
在页面中这样输入就能得到想要的数据

加密页码形式:
from rest_framework.pagination import CursorPagination class MyPageNumberPagination(CursorPagination): cursor_query_param="page" page_size=2 ordering="id"
页码的显示形式: 所以不能用户自己输入页面,只能通过点击链接跳转页码





浙公网安备 33010602011771号