一 路由Routers
对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。
REST framework提供了两个router
- SimpleRouter
- DefaultRouter
1-1 具体使用方法:
(1): 在urls.py中配置(回顾)
url(r'^books3/', views.BooksAPIView.as_view()),
url(r'^book3/(?P<pk>d+)', views.BookAPIView.as_view()),
(2) :一旦视图类继承了ViewSetMixin,路由会: (回顾)
url(r'^books4/', views.Book4View.as_view(actions={'get':'list','post':'create'})),
url(r'^book4/(?P<pk>d+)', views.Book4View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'}))
class BookViewSet(ModelViewSet):
queryset =Book.objects.all()
serializer_class = BookSerializer
(3): 继承自视图类,自动生成路由(重点):
3-1: 在urls.py中.导入routers模块
from rest_framework import routers
3-2: 模块;里面两个类,实例化得到对象:
routers.DefaultRouter ---->自动生成6条路由
routers.SimpleRouter ----->自动生成2条路由(用它即可)
router=routers.SimpleRouter()
3-3: 注册
router.register('前缀','继承自ModelViewSet视图类','别名')
router.register('books',views.BookViewSet) 不用加斜杠了
3-4: 把自动生成的路由,加到原路由中:
urlpatterns+=router.urls
二 action的使用
用途: 为了给继承自ModelViewSet的视图类中定义的函数也添加路由,因为我们自动生成的质保函视图类,但是视图类中方法他自动生成不了路由.
如:中get_1方法就自动生成不了路由.
class BookViewSet(ModelViewSet):
queryset =Book.objects.all()
serializer_class = BookSerializer
def get_1(self,request,pk):
book=self.get_queryset()[0:10] ---->表示取10条数据
ser=self.get_serializer(book,many=True)
return Response(ser.data)
解决: @action(methods=['GET','POST'],detail=True)---->装饰器
method:请求方式, detail:是否带pk
@action(methods=['GET','POST'],detail=True)
def get_1(self,request,pk):
book=self.get_queryset()[:2] # 从0开始截取一条
ser=self.get_serializer(book,many=True)
return Response(ser.data)
三 认证
3-1 认证的大致思路:
(1) 写一个类,继承BaseAuthentication,重写authenticate,认证的逻辑写在里面,认证通过,返回两个值,一个值最终给了Requet对象的user,认证失败,抛异常:APIException或者AuthenticationFailed
(2) 全局使用,局部使用.
3-2 认证的实现
(1): 认证前的准备
登录功能:
class User(models.Model):
username=models.CharField(max_length=32)
password=models.CharField(max_length=32)
user_type = models.IntegerField(choices=((1, '超级用户'), (2, '普通用户'), (3, '二笔用户')))
class UserToken(models.Model):
token=models.CharField(max_length=64)
user=models.OneToOneField(to=User,on_delete=models.CASCADE)
from app01 import models
import uuid
class LoginView(APIView):
def post(self,request):
# 通过request.data拿到user和pwd
username=request.data.get('username')
password=request.data.get('password')
# 验证
user=models.User.objects.filter(username=username,password=password).first()
if user:
token=uuid.uuid4()
models.UserToken.objects.update_or_create(defaults={'token':token},user=user)
return Response({'statue':100,'msg':'登录成功','token':token})
else:
return Response({'statue':101,'msg':'账号或密码错误'})
(2): 认证
新建一个py文件,写一个认证类
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
token=request.GET.get('token')
if token:
user_token=UserToken.objects.filter(token=token).first()
if user_token:
return user_token.user,token
else:
raise AuthenticationFailed('认证失败')
else:
raise AuthenticationFailed('请求地址中需要token')
(3):全局使用:
在setting.py中配置
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}
但是要注意,全局使用登录功能也会执行,但是没有登录,怎么认证,所以需要局部禁用:
局部禁用
authentication_classes=[]
class LoginView(APIView):
authentication_classes = []
def post(self,request):
# 通过request.data拿到user和pwd
username=request.data.get('username')
password=request.data.get('password')
# 验证
user=models.User.objects.filter(username=username,password=password).first()
if user:
token=uuid.uuid4()
models.UserToken.objects.update_or_create(defaults={'token':token},user=user)
return Response({'statue':100,'msg':'登录成功','token':token})
else:
return Response({'statue':101,'msg':'账号或密码错误'})
局部使用:
直接在视图类上写即可:
authentication_classes=[MyAuthentication]
作业:
登陆接口,查询图书接口,必须登录后才能查看,token信息放在头里(认证组件),全局使用,局部禁用(login禁用)