路由

只要继承了ViewSetMixin及其子类的视图类就能自动生成路由

自动生成路由

from rest_framework.routers import SimpleRouter, DefaultRouter
SimpleRouterDefaultRouter的区别
DefaultRouterSimpleRouter多一个根路径,显示所有注册过的路由

自动生成路由的写法
1.导入模块:from rest_framework.routers import SimpleRouter, DefaultRouter
2.实例化:router = SimpleRouter()  # router=DefaultRouter()
3.注册:router.register('user',views.UserView,'user')
4.加入到urlpatterns中(两种方式)
    4.1.urlpatterns += router.urls
    4.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)
"""
action装饰器的使用

from rest_framework.decorators import action
在视图函数中 会有一些其它名字的方法 必须要使用action装饰器做映射
在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action装饰器
以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。

  • 装饰器的参数
methods: 支持的请求方式,列表或元组类型
detail: 默认是False 控制生成的路由是不是带pk
    False: /user/login/
    True:/user/pk/login/
url_path: 控制生成的/user/后的路径是什么,如果不写,默认以方法名命名
    /user/login/,一般跟函数名同名即可
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

PS: 这样写了以后可以 自动生成路由

登录接口编写

  • module.py
用户表
class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    def __str__(self):
        return self.username
# 用户登录记录表
# 如何区分用户是否登录了?
class UserToken(models.Model):
    user = models.OneToOneField(to='User', on_delete=models.CASCADE)
    token = models.CharField(max_length=32, null=True)  # 用户如果没有登录,就是空,如果登录了,就有值,登录多次以最后一次为准
  • views.py
class UserView(ViewSet):
    authentication_classes = []
    @action(methods=['POST', ], detail=False, url_path='login')
    def login(self, request):
        # 取出前端传入的用户名密码,校验,通过,返回登录成功,失败就返回用户名密码错误
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            # 登录成功,不同的人生成的token是不一样的,谁登录的,就把token存到UserToken表中
            token = str(uuid.uuid4())  # 生成一个永不重复的随机字符串
            # 存UserToken:如果没有记录,就是新增,如果有记录更新一下即可
            # 通过user去UserToken表中查数据,如果能查到,使用defaults的数据更新,如果查不到,直接通过user和defaults的数据新增
            UserToken.objects.update_or_create(defaults={'token': token}, user=user)
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})
  • urls.py
from rest_framework.routers import SimpleRouter, DefaultRouter
from django.conf.urls import include

router = SimpleRouter()

router.register('user',views.UserView,'user')

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

认证

  • 认证类

访问接口的时候,必须登录后才能访问。我们可以通过认证类完成这一需求
需要导入from rest_framework.authentication import BaseAuthentication

from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed


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

1.写一个认证类,继承BaseAuthentication
2.重写authenticate方法,在内部做认证
3.如果认证通过,返回2个值
4.认证不通过抛AuthenticationFailed异常
5.只要返回了两个值,在后续的request.user 就是当前登录用户
6.如果想让某个视图类登录后才能访问

方式一: 局部配置
    class BookView(ModelViewSet):
        authentication_classes = [LoginAuth,]

方式二: 全局配置
    REST_FRAMEWORK={
        'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.LoginAuth',]
    }

局部禁用:
    class BookView(ModelViewSet):
        authentication_classes = []

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 on 2022-10-08 20:53  Joker_Ly  阅读(11)  评论(0)    收藏  举报