drf路由和三大认证之认证

自动生成路由

必须继承了ViewSetMixin以及子类的视图类才能自动生成路由

路由Routers

对于视图集ViewSet,我们除了可以自己动手指名请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息

rest_framework提供了两个router类

  • SimpleRouter
  • DefaultRouter

使用方法

  1. 导入
from rest_framework.routers import SimpleRouter,DefaultRouter
  1. 实例化
# router=DefaultRouter()
router=SimpleRouter()
  1. 注册
router.register('user',views.UserView,'user')
  1. 加入到urlpatterns
方式1:urlpatterns+=router.urls

方式2:在urlpatterns添加:path('', include(router.urls))

注意

自动生成的路由映射关系其实定死了

/books/    {'get':'list'}
/books/    {'post':'create'}
/books/1/  {'get':'retrieve'}
/books/1/  {'put':'update'}
/books/1/  {'delete':'destroy'}

所以,以后写的视图类不需要写action装饰器的话,视图类中必须要有(当然我们也可以通过action装饰器映射路由)

list、destory、retrieve、create、update方法之一

其实是必须是5个扩展类之一+GenericAPIView,或9个视图子类(ModelViewSet)

SimpleRouter和DefaultRouter的区别

DefaultRouter和SimpleRouter多一个根路径,显示所有注册过的路由

action装饰器的使用

使用场景

在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action装饰器

以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。

action装饰器方法的参数

  • methods:支持的请求方式,列表或元素类型
  • detail:默认是False,控制生成的路由是不是带pk
False: /user/login/
True:/user/pk/login/
  • url_path:控制生成的/user/后的路径是什么,如果不写,默认以方法名命名
  • url_name:别名,用于反向解析

案例

# views.py

class UserDetail(ViewSet):
    authentication_classes = []
    @action(methods=['GET',],detail=False)
    def show(self,request):
        return Response('show user_info')
      
# urls.py

from app01 import views
from rest_framework.routers import SimpleRouter,DefaultRouter
router=DefaultRouter()
router.register('user_detail',views.UserDetail,'user_detail')

urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns+=router.urls

登录接口编写

models.py

# 用户表
class User(models.Model):
    username=models.CharField(max_length=32)
    password=models.CharField(max_length=32)

# 用户登录记录表
# 如何区分用户是否登录了
class UserToken(models.Model):
    user=models.OneToOneField(to=User,on_delete=models.CASCADE)
    token=models.CharField(max_length=50) # 用户如果没有登录,就是空,如果登录了,就有值,登录多次以最后一次为准

views.py

class UserView(ViewSet):
    authentication_classes = []
    @action(methods=['POST',],detail=False)
    def login(self,request):
      # 取出前端传入的用户名密码,校验,通过,返回登录成功,失败就返回用户名密码错误
        username, password = request.data.get('username'), request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            # 登录成功,不同人生成的token是不一样的,谁登录的,就把token存到UserToken表中
            token = str(uuid4())  # 生成一个永不重复的随机字符串
            # 存UserToken:如果没有记录,就是新增,如果有记录更新一下即可
            # 通过user去UserToken表中查数据,如果能查到,使用defaults的数据更新,如果查不到直接通过user和defaults的数据新增
            # defaults,更新或创建的数据
            # kwargs,依据此查询
            UserToken.objects.update_or_create(defaults={'token': token}, user=user)
            return Response('登录成功')
        else:
            raise ValidationError('用户名或密码错误')
            

urls.py

from rest_framework.routers import SimpleRouter,DefaultRouter
router=DefaultRouter()
router.register('user',views.UserView,'user')
urlpatterns+=router.urls

认证

访问接口的时候,必须登录后才能访问。我们可以通过认证类完成这一需求

使用步骤

  1. 写一个认证类,继承BaseAuthentication
  2. 重写authenticate方法,在内部做认证
  3. 如果认证通过,返回2个值
  4. 认证不通过抛AuthenticationFailed异常
  5. 只要返回了两个值,在后续的request.user就是当前登录用户
  6. 如果先让某个视图类登录后才能访问
局部配置
	class UserView(ViewSet):
    authentication_classes = [LoginAuth,]

全局配置
	REST_FRAMEWORK={
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'app01.auth.LoginAuth'
    ]
}
局部禁用
	authentication_classes = []

认证类

from rest_framework.authentication import BaseAuthentication
from .models import User,UserToken
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.exceptions import ValidationError
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
      # 在这里做认证,校验用户是否登录(带了token,并且能查到,就是登录,返回两个值,否则就是没登录,抛异常)
       # 用户带的token从哪取?后端人员定的:放在请求地址中
        token=request.query_params.get('token')
        # 通过token查询该token是否在表中有记录
        user_token=UserToken.objects.filter(token=token).first()
        if user_token:
            return user_token.user,token  返回两个值,一个是当前登录用户,一个是token
        else:
            raise AuthenticationFailed('你尚未登录')

on_delete

1、models.CASCADE
    级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
2、models.SET_NULL
    当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
3、models.PROTECT
    当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
4、models.SET_DEFAULT
    当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
5、models.SET()
    当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
6、models.DO_NOTHING
    什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
posted @ 2022-10-08 22:05  荀飞  阅读(44)  评论(0编辑  收藏  举报