drf知识-06

发布时间:2023年12月26日

视图集

#1 ?ModelViewSet:
视图类:GenericAPIView
映射:list ?create ?retrieve update destroy
#2 ?ViewSetMixin类: 只要继承它,路由写法变了? ? ? ? ?
? ? 分析:ViewSetMixin ?不是视图类,支持路由映射的写法,核心原理是重写了as_view?
? ? ?? ??? ?以后路由写法as_view必须传字典,映射关系
? ? ? ? ?? ?什么请求方式就执行视图类中什么方法的映射关系 ?

? ??? ?@classonlymethod
? ? def as_view(cls, actions=None, **initkwargs):
? ? ? ? # actions={'get': 'list', 'post': 'create'}
? ? ? ?def view(request, *args, **kwargs):
? ? ? ? ? ? self = cls(**initkwargs) ?# self 是BookView 视图类的对象
? ? ? ? ? ? self.action_map = actions
? ? ? ? ? ? for method, action in actions.items():
? ? ? ? ? ? ? ? # method:get ? action:list
? ? ? ? ? ? ? ? # 去视图类的对象中 self中 反射list方法---》有--》
? ? ? ? ? ? ? ? # handler 就是 BookView的对象中得list方法
? ? ? ? ? ? ? ? handler = getattr(self, action)
? ? ? ? ? ? ? ? # 反射,设置值---》把method:get,设置成了 list
? ? ? ? ? ? ? ? #BookView类的对象,以后get方法就是list方法
? ? ? ? ? ? ? ? setattr(self, method, handler)
? ? ? ? ? ? # 根据请求方式执行跟请求方式同名的方法 ?get请求---》get方法---》list
? ? ? ? ? ? return self.dispatch(request, *args, **kwargs)

#3 ?ViewSet:以后想继承APIView,但是路由写变了,就继承它
#4 ?GenericViewSet:以后想继承GenericViewSet,但是路由写变了,就继承它
#5 ReadOnlyModelViewSet:只读
? ? 视图类:GenericAPIView
? ? 映射:list ? ?retrieve :只查询,查询所有和查询单条ListModelMixin,RetrieveModelMixin
? ? 路由写法变了:ViewSetMixin

小案例选择哪些视图类继承

### 现在有很多视图类,不知道选哪个,具体实战
# 1 publish的5个接口:

????????ModelViewset

# 2 publish的5个接口,获取所有,带code和msg:

????????ModelViewset重写list

def list(self, request, *args, **kwargs):
? ? res = super().list(request, *args, **kwargs)
? ? return Response({'code': 100, 'msg': '查询所有成功', 'result': res.data})

# 3 写 查询所有,修改一条,路由写法变了
? ? ViewSetMixin, GenericAPIView
? ? ListModelMixin,UpdateModelMixin

# class BookView(ViewSetMixin, GenericAPIView,ListModelMixin,UpdateModelMixin):
class BookView(GenericViewSet,ListModelMixin,UpdateModelMixin):
? ? queryset = Book.objects.all()
? ? serializer_class = BookSerializer

路由:
? ?path('books/', views.BookView.as_view({'get': 'list'})),
? ?path('books/<int:id>', views.BookView.as_view({'put': 'update'})),

# 4 用户视图类,有登录(login)和注册(register)接口


?

class UserView(ViewSet):
? ? def login(self):
? ? ? ? pass
? ? def register(self):
  ? ? ? pass

# path('login/', views.UserView.as_view({'post': 'login'})),
# path('register/', views.BookView.as_view({'post': 'register'})),

# 5 新增一条图书,路由写法变了

from rest_framework.generics import CreateAPIView
class BooView(ViewSetMixin,CreateAPIView):
? ? queryset = None
? ? serializer_class = None
? ? #path('books/', views.UserView.as_view({'post': 'create'})),

# 6 查询一条和删除

from rest_framework.generics import RetrieveDestroyAPIView
class BooView(RetrieveDestroyAPIView):
class BooView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin):
? ? queryset = None
? ? serializer_class = None

视图层总结

# 视图层:
# 两个视图基类
?? ?APIView
? ? GenericAPIView
# 5个视图扩展类---》不是视图类,必须结合GenericAPIView
? ? ? ? CreateModelMixin:create---》原来咱们post中得代码,新增
? ? ? ? ListModelMixin:list---》原来获取所有
? ? ? ? RetrieveModelMixin:retrieve---》原来获取单条
? ? ? ? UpdateModelMixin:update--->修改
? ? ? ? DestroyModelMixin:destroy--》删除
# 9个视图子类
?? ? ? ?CreateAPIView
? ? ? ? ListAPIView
? ? ? ? RetrieveAPIView
? ? ? ? DestroyAPIView
? ? ? ? UpdateAPIView
? ? ? ? ListCreateAPIView
? ? ? ? RetrieveUpdateDestroyAPIView
? ? ? ? RetrieveDestroyAPIView
? ? ? ? RetrieveUpdateAPIView? ? ? ? ? ?
# 视图集
?? ?ModelViewSet:
? ? ReadOnlyModelViewSet:
? ? ViewSetMixin:路由写法变了
? ? ViewSet:ViewSetMixin+APIView
? ? GenericViewSet:ViewSetMixin+GenericAPIView

drf之路由

# 视图类没有继承了ViewSetMixin,路由写法跟之前一样
?? ?path('books/', views.BookView.as_view())
#? 只要视图类继承了ViewSetMixin,路由写法必须写成映射的方式
?? ?path('books/', views.BookView.as_view({'get': 'list'})),
#?只要视图类继承了ModelViewSet,还可以这么写:

路由:
from rest_framework.routers import SimpleRouter  #1 导入
router = SimpleRouter()   #2 实例化
router.register('books', views.BookView, 'books')    #3 注册路径,action装饰器
urlpatterns = [
]
urlpatterns += router.urls    #4 加入到路由中
 
视图类:
from .models import Book
from .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    # 5 list,create,retrieve,destroy,update自动映射--》SimpleRouter
    serializer_class = BookSerializer 
    @action(methods=['POST'],detail=False,)
? ? def login(self,request):
? ? ? ? return Response('login')

# 3 假设视图类中有个login,如何做对应?

from rest_framework.decorators import action
class BookView(ModelViewSet):
? ? queryset = Book.objects.all()
? ? serializer_class = BookSerializer
? ? #methods=None, 请求方式
? ? # detail=None, ?只能写True或False,如果写了false就是不带pk的路径,如果写了True路径带pk
? ? ?? ?# False的情况: http://127.0.0.1:8080/api/v1/books/login/
? ? ? ? # True 的情况: http://127.0.0.1:8080/api/v1/books/8/login/
? ? # url_path='login' 路径,会在之前的路径上,拼这个路径,如果不写默认以函数名拼接
? ? ? ? # - http://127.0.0.1:8080/api/v1/books/login/
? ? # url_name=None :别名,用做反向解析
? ? @action(methods=['POST'],detail=False,)
? ? def login(self,request):
? ? ? ? return Response('login')

# 4 总结:以后只要继承ViewSetMixin,就可以使用SimpleRouter方式写路由

from rest_framework.routers import SimpleRouter,DefaultRouter  #1 导入
SimpleRouter,DefaultRouter     #2 实例化
router = SimpleRouter()
# router = DefaultRouter()
router.register('books', views.BookView, 'books')   #3 注册路径,action
#4 加入到路由中:
# 方式一:(用这个)
urlpatterns += router.urls
# 方式二:
urlpatterns = [
? ? path('', include(router.urls)),
]

# 5 list,create,retrieve,destroy,update--->自动映射--》SimpleRouter
# 6 视图类中自己的方法,再做映射--action装饰器

@action(methods=['POST'],detail=False,)
def login(self,request):
? ? return Response('login')

认证组件之登录认证

# 登录认证:
? ?登录进系统后,以后再访问接口,需要携带登录信息,如果没携带,不允许
? ? cookie(客户端浏览器上)和session(后端存储的键值对)
# 写个登录

from django.contrib import admin
from django.urls import path, include
from . import views
from rest_framework.routers import SimpleRouter, DefaultRouter

router = SimpleRouter()   # 实例化
router.register('books', views.BookView, 'books')    # 注册路径
# http://127.0.0.1:8080/api/v1/users/login---->post 请求就执行UserView的login方法
router.register('users', views.UserView, 'users')
urlpatterns = [
    path('', include(router.urls)),
]   # urlpatterns += router.urls
# 登录,对照数据库用户名或密码,若正确更新或添加token
from rest_framework.decorators import action
from .models import User, UserToken
import uuid
class UserView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        # 前端传入的username和password  request.data
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(name=username, password=password).first()
        if user:
            token = str(uuid.uuid4())
            # 如果之前UserToken表中有记录,就要更新,如果没有记录,就要新增
            UserToken.objects.update_or_create(defaults={'token': token}, user_id=user.pk)
            return Response({'code': '100', 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': '101', 'msg': '用户名或密码错误'})

# 后续访问某些接口,携带登录信息--->session--->后端校验(认证组件)

# 认证组件步骤:
?? ?1 写个认证类,继承BaseAuthentication
? ? 2 在类中重写 authenticate,在方法中完成认证,通过返回两个值,失败抛异常? ? ?

# 必须有token才能登录,通过token去user
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import User, UserToken
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 完成对用户的校验
        # 当次请求request
        token = request.query_params.get('token')
        # 表中校验
        user_token = UserToken.objects.filter(token=token).first()
        # 当前登录用户
        if user_token:
            user = user_token.user
            # 校验过后,返回两个值
            return user, user_token
        else:
            raise AuthenticationFailed("您没有登录")

3 使用认证类:放在需要登录后才能访问的视图类上

from .auth import LoginAuth
class BookView(ReadOnlyModelViewSet):  # list  retrieve
    authentication_classes = [LoginAuth]  # 5个接口必须登录才能呢访问
    # 配置两个类属性
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 重写list添加了信息显示
    def list(self, request, *args, **kwargs):
        res = super().list(request, *args, **kwargs)
        return Response({'code': 100, 'msg': '查询所有成功', 'result': res.data})

今日思维导图:

文章来源:https://blog.csdn.net/qq_48064830/article/details/135224400
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。