DRF-ModelViewSet

一、九个视图子类

不用自己再写get,post,put等方法,视图子类给我们封装了

from rest_framework.generics import GenericAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView, ListAPIView, \
    UpdateAPIView, DestroyAPIView, RetrieveAPIView, CreateAPIView,RetrieveDestroyAPIView

九个视图子类继承了GenericAPIView,所以写类时可以不用写GenericAPIView

## 路由
urlpatterns = [
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookView.as_view()),
]

# 视图类
class BookView(ListCreateAPIView):  # 查询所有,新增一个
    queryset = Book.objects.all()
    serializer_class = BookSerializer


# 新增一个,修改一个,删除一个
class BookDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

二、ModelViewSet(重点)

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    
发现ModelViewSet继承了五个学过的视图类

继承ModelViewSet后,五个接口都写好了,但是路由需要配置一下

因为ModelViewSet里面的ViewSetMixin重写了as_view方法,并且该父类写在另一个父类的左边,所以就先执行ViewSetMixin的as_view了

路由中需要给as_view()配置actions={},用来控制执行的方法,不然就会报异常

但是又发现如果只开一个路由,get有两个冲突,再重新开一条路由,调用同一个视图类

先导一下
from rest_framework.viewsets import ModelViewSet

class BookView(ModelViewSet):
    queryset = Book.object
    serializer_class = BookSerializers
    
#路由层
urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BooksView.as_view(actions={'get': 'list', 'post': 'create'})),
    # path('books/<int:pk>/',views.BookDetailView.as_view()),
    path('books/<int:pk>/', views.BooksView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
]



1.裂变,只读,两个接口的
导入一下
from rest_framework.viewsets import ReadOnlyModelViewSet

只读————ReadOnlyModelViewSet

2.ViewSetMixin高级用法(高级,重要)

只要继承了ViewSetMixin,并且必须写在APIVIEW或者GenericAPIView前面!!!

就可以根据自己需要,改写list等方法,可以任意命名,因为反正路由那边是根据K:V的形式来做映射

可以基于ViewSetMixin玩一玩,这个就只是改写as_view方法达到映射,比如我们搭配APIVIEW来玩玩,配一下get对应的方法即可
from rest_framework.viewsets import ViewSetMixin


class TestView1(ViewSetMixin, APIView):# 也等于ViewSet
    def hahaha(self, request):
        print('你最好小心一点')
        return Response('你最好小心一点')
3.重点
from rest_framework.viewsets import ViewSet,GenericViewSet
总结:
ViewSetMixin + APIVIEW =  ViewSet
ViewSetMixin + GenericAPIView = GenericViewSet



"""
	以后,你想继承APIView,但是想变路由写法【视图类中方法名任意命名】,要继承ViewSet
    以后,你想继承GenericAPIView,但是想变路由写法【视图类中方法名任意命名】,要继承GenericViewSet
"""

三、视图类大总结!

1.两个视图基类
-APIView,GenericAPIView
2.五个视图拓展类,必须配合GenericAPIView

​ 这个用不上了,已经有九个视图子类能完美替代

3.9个视图子类
4.视图集
-ModelViewSet:路由写法变了,只需要写两行,5个接口都有了

-ReadOnlyModelViewSet:路由写法变了,只需要写两行,2个只读接口都有了

-ViewSetMixin:不是视图类,魔法,重写了as_view,路由写法变了,变成映射了
	
-ViewSet:ViewSetMixin+ APIView
-GenericViewSet:ViewSetMixin+ GenericAPIView
总结:
1.小功能不和数据库打交道可以ViewSet,然后自己写见名只知意的方法
   和数据库打交道可以GenericViewSet
因为用GenericViewSet必须配置那个表,就相当于查了一遍表,占用资源
2.如果要写一个视图类只要一个或一两个方法,直接继承9个视图子类里面的

四、路由系统

能自动生成路由的方法
视图层类要继承ModelViewSet
1.然后路由层,导入路由类
.routers import SimpleRouter # 这个生成两个路由,常用 
.routers import DefaultRouter # 这个生成的路由好多个,不太常用

2.实例化一个路由器对象
router = SimpleRouter()

3.注册,让路由对应视图类,有几个视图类就要写几次
router.register('books',views.BookView)
这个括号内还可以写第三个参数,类似反向解析,直接写就行不用写name=啥

4.填入路由层的匹配列表
有两种方式,第二种用的多一些
 urlpatterns += router.urls
 # include 需要导入一下,from django.urls import path,include
path('api/v1/',include(router.urls)) 

5.注意使用第二种方法后,要打全api/v1/才能进去根页面

DefaultRouter和根

DefaultRouter能生成很多个路由,并且在你的api的根首页,可以看到你整体api的地址

总结
本质是自动做映射,能够自动成的前提是,视图类中要有 5个方法的某要给或多个

1.ModelViewSet,ReadOnlyModelViewSet可以自动生成
              
2.9个视图子类+配合ViewSetMixin   才可以自动生成
  比如
class PublishView(ViewSetMixin,ListAPIView):
    queryset = Publish.objects
    serializer_class = PublishSerializers

3.GenericAPIView+5个试图扩展类+配合ViewSetMixin   才能自动生成

五、actions装饰器

​ 如果想写一个或者两个的普通视图类,用ViewSetMixin做映射,写点方法,发现正常写路由层的actions={}可以实现,但是想偷懒,想后期都不在动路由层的urlpatterns,这时候就可以用到装饰器

1.导一下
from rest_framework.decorators import action
2.我们学习一下action的参数
	methods=[]  是指定使用这个装饰器的方法映射原来的哪个属性
  	detail=True/False 
    	False是不带ID(PK之类的)的路径
        	send/send_msg
         True是带ID的路径,写了后一定要给被装饰函数增加形参
        	send/pk/send_msg
    url_path:生成send后路径的名字,默认以方法名命名 
    url_name:别名,反向解析使用,了解即可
    
    
class SendView(ViewSet):
    @action(methods=['GET'], detail=False)
    def send_msg(self, request):
        name = request.query_params.get('name')
        phone = request.query_params.get('phone')
        return Response({'code': 100, 'msg': [name,phone]})    

 # 补充:
	-1 不同请求方式可以使用不同序列化类
    -2 不同action使用不同序列化类
class SendView(GenericViewSet):
    queryset = None
    serializer_class = '序列化类'

    def get_serializer(self, *args, **kwargs):
        if self.action=='lqz':
            return '某个序列化类'
        else:
            return '另一个序列化列'
    @action(methods=['GET'], detail=True)
    def send_sms(self, request,pk):
        print(pk)
        # 手机号,从哪去,假设get请求,携带了参数
        phone = request.query_params.get('phone')
        print('发送成功,%s' % phone)
        return Response({'code': 100, 'msg': '发送成功'})

    @action(methods=['GET'], detail=True)
    def lqz(self,request):  # get
        # 序列化类
        pass

    @action(methods=['GET'], detail=True)
    def login(self,request):  # get
        # 序列化类
        pass

六、认证组件

前戏

​ 写一个登录功能接口

1.写呗,涉及数据,先建立表
class User(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=32)

class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to='User',on_delete=models.CASCADE,null=True)
    
2.写视图类
class UserView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        username = request.data.get('name')

        password = request.data.get('password')

        user_obj = User.objects.filter(name=username, password=password).first()
        if user_obj:

            res = str(uuid.uuid4())
            obj = UserToken.objects.filter(user=user_obj)
            if obj:
                UserToken.objects.update(user=user_obj,token=res)
                return Response({'code': 100, 'msg': '登录成功,欢迎回来'})
            else:
                UserToken.objects.create(user=user_obj,token=res)
                return Response({'code': 100, 'msg': '登录成功'})
            
            
          	# 高级写法,不用if  update_or_create 如果有就修改,如果没有就新增  
            # kwargs 传入的东西查找,能找到,使用defaults的更新,否则新增一条
            # UserToken.objects.update_or_create(user=user_obj, defaults={'token': res})

        else:
            return Response({'code': 101, 'msg': '登录失败'})
3.写路由
router.register('user',views.UserView,'login')
4.POSTMAN验证,地址写对啊!
http://127.0.0.1:8000/api/v1/user/login/,然后传数据到后端

今日单词

generics  泛型  放GenericAPIView和九个视图子类的地方
Router 路由器
ViewSetMixin  来自viewsets,用来映射路由

今日注意

1.注意使用路由自动添加第二种方法include后,要打全api/v1/才能进去根页面
2.request.query_params是request.GET的一个更准确的同义词。包含了所有用过get方式请求的参数,用来取字符串,携带在网址?后面的东西
3.注册路由时router.register('send', views.SendView,basename='send') 第三个参数带上最好,不然可能会报错
4.不同action使用不同序列化类不是很能理解

今日补充

1.on_delete=models. 级联更新级联删除这里,还有SET_NULL SET_DEFAULT
SET(函数内存地址)
	因为不可能一个作者被删除了,所有书都被删除了
2.uuid模块,能生成uuid4()对象,是一个随机字符串,记得转str
3.update_or_create 如果有就修改,如果没有就新增 

作业

class UserView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        username = request.data.get('name')

        password = request.data.get('password')

        user_obj = User.objects.filter(name=username, password=password).first()
        if user_obj:

            res = str(uuid.uuid4())
            obj = UserToken.objects.filter(user=user_obj)
            # user_token_obj = UserToken.objects.create(user=user_obj, token=res)
            if obj:
                UserToken.objects.update(user=user_obj,token=res)
                return Response({'code': 100, 'msg': '登录成功,欢迎回来'})
            else:
                UserToken.objects.create(user=user_obj,token=res)
                return Response({'code': 100, 'msg': '登录成功'})

        else:
            return Response({'code': 101, 'msg': '登录失败'})

分类: drf项目

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值