今日内容概要
内容详细
1、视图组件
# 9个视图子类--是视图类
from rest_framework.generics import
CreateAPIView,
ListAPIView,
DestroyAPIView,
RetrieveAPIView,
UpdateAPIView,
ListCreateAPIView,
RetrieveUpdateAPIView,
RetrieveUpdateDestroyAPIView,
RetrieveDestroyAPIView
第四层: 通过9个视图子类,重写视图函数 views.py:
# 第四层:通过9个视图子类,重写视图函数
# 9个视图子类
from rest_framework.generics import CreateAPIView, ListAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView
class PublishView(ListCreateAPIView): # 查询所有和新增接口就有了
# class PublishView(CreateAPIView): # 新增接口就有了
# class PublishView(ListAPIView): # 查询所有接口就有了
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
class PublishDetailView(RetrieveUpdateDestroyAPIView): # 查询单条,删除,修改 接口就都有了
# class PublishDetailView(RetrieveAPIView): # 查询单条 接口就有了
# class PublishDetailView(DestroyAPIView): # 删除 接口就有了
# class PublishDetailView(UpdateAPIView): # 修改 接口就有了
# class PublishDetailView(RetrieveDestroyAPIView): # 查询单条和删除 接口就有了
# class PublishDetailView(RetrieveUpdateAPIView): # 查询单条和更新 接口就有了
# class PublishDetailView(UpdateAPIView,DestroyAPIView): # 更新和删除 接口就有了
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
# 但是页有可能要重写--》get_queryset--》get_serializer_class--》perform_create--》get,post等方法
第五层: 通过ViewSet,重写视图函数 views.py:
# 第五层:通过ViewSet写视图类
# 5个接口,都用一个视图类----》导致了路由问题:有两个get
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
"""
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.viewsets import ViewSetMixin
ViewSet=APIView+ViewSetMixin
GenericViewSet=GenericAPIView+ViewSetMixin
以后只要想自动生成路由,必须继承ViewSetMixin及其子类
之前的写法可以沿用,只是如果要自动生成路由可以选择继承ViewSet 或者 GenericViewSet
"""
class PublishView(ModelViewSet): # 修改路由,5个接口都有
# 继承了5个视图扩展类+GenericViewSet(ViewSetMixin, generics.GenericAPIView)
# 其中 ViewSetMixin-->控制了路由写法变了
# class PublishView(ReadOnlyModelViewSet): # 修改路由,只有 查所有,查单个两个接口
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
##### 在urls.py中配置 加入方式一:
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('publish', views.PublishView, 'publish')
# 然后要把路由加入到urlpatterns的列表中 两种方式
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/', views.BookView.as_view()),
]
# 加入方式一
# router.urls 他会自动生成列表 包含两种地址: publishs / publishs/
# print(router.urls) # [, [^/.]+)/$' [name='publish-detail']>]
urlpatterns += router.urls # 两个列表相加
##### 在urls.py中配置 加入方式二:
from django.urls import include
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('publish', views.PublishView, 'publish')
# 然后要把路由加入到urlpatterns的列表中 两种方式
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/', views.BookView.as_view()),
# 加入方式二:
path('api/v1/', include(router.urls)), # from django.urls import include
# 这样写等用于下面两句 ''引号中可以随意加入前缀 # 但是默认就有: publishs / publishs/
# path('api/v1/publishs/', views.PublishView.as_view()),
#
# path('api/v1/publishs/', views.PublishDetailView.as_view()),
]
2、路由组件
# 只要继承ViewSetMixin 及其子类,路由写法就变了
# 视图类只要继承ViewSetMixin,路由写法就变了 而且视图类中的方法不一定写成get,post.. 可以随意命名 路由改为:
path('login/', views.TestView.as_view({'get': 'login'})), # 意思为:get请求来了,执行视图类中的login方法
# 如何执行的?源码分析
ViewSetMixin必须写在前面
as_view--->类的查找顺序
actions就是传入的字典---》view闭包函数:
def view(request, *args, **kwargs):
# get login
for method, action in actions.items():
# 把login方法的内存地址给了handler
handler = getattr(self, action)
# 通过反射,设置给get---》对应login---》get请求执行get方法,现在get方法变成了login方法
setattr(self, method, handler)
return self.dispatch(request, *args, **kwargs)# 跟之前一样了
演示继承 ViewSetMixin类 的路由写法:
### views.py中:
from rest_framework.viewsets import ViewSetMixin, ViewSet, GenericViewSet
from rest_framework.views import APIView
from rest_framework.decorators import action
class TestView(ViewSetMixin, APIView): # ViewSetMixin必须写在前面
# class TestView(ViewSet): # 等同于上面 class TestView(ViewSetMixin, APIView)
# class TestView(ViewSetMixin, GenericAPIView): # 只要继承ViewSetMixin的 该类就必须写在前面
def login(self, request):
return Response("get-login")
# 路由中 urls.py:
# 路由组件:
path('login/', views.TestView.as_view({'get': 'login'})), # 意思为:get请求来了,执行视图类中的login方法
继承ModelViewSet 类,路由写法:
# views.py:
# 路由组件
class PublishView(ModelViewSet): # 修改路由,5个接口都有
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
# urls.py:
path('publish/', views.PublishView.as_view({'get': 'list', 'post': 'create'})),
path('publish/', views.PublishView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
总结:
# 上面的两个路由,是可以自动生成的:
第一步:导入drf提供的路由类
from rest_framework.routers import SimpleRouter
第二步:实例化得到对象
router = SimpleRouter()
第三步:注册路由
router.register('地址', 视图类, '别名')
router.register('publish', views.PublishView, 'publish')
第四步:在urlpatterns加入(两种方式)
path('/api/v1', include(router.urls))
urlpatterns+=router.urls
# SimpleRouter类 和 DefaultRouter类
用法完全一样 只是生成的路由不一样
DefaultRouter 比 SimpleRouter多一条根地址,一般咱么就用 SimpleRouter就可以
# 如果使用自动生成路由,必须继承谁及其子类?
GenericViewSet + 5个视图扩展类至少之一 才能自动生成
# action装饰器
# action装饰器 可以再生成路由 记得要修改路由为自动生成模式
from rest_framework.decorators import action
class TestView(ViewSetMixin, APIView): # ViewSetMixin必须写在前面
# action的默认参数:
# methods=请求方法,列表, detail=是否带id, url_path=地址如果不写,默认已方法名为地址, url_name=别名
# 写成如下,自动生成路由会生成一条路由:127.0.0.1:8080/test/login -->get,post都会触发
@action(methods=['GET', 'POST'], detail=False)
def login(self, request):
return Response("get-login")
# 如果写法如下,生成的路径是127.0.0.1:8080/test/数字/login
@action(methods=['GET', 'POST'], detail=True)
def login(self, request):
# 使用action,怎么通过action判断?
重写 get_queryset、get_serializer_class
class TestView2(GenericViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get_queryset(self):
# 根据请求地址,返回的get_queryset不一样
if self.action=='login':
return Author.objects.all()
else:
return self.queryset
def get_serializer_class(self):
if self.action=='login':
return AuthorSerialzier
else:
return BookSerializer
@action(methods=['GET','POST'],detail=True)
def login(self,request):
obj=self.get_queryset()
return Response("get-login")
@action(methods=['GET'], detail=True)
def test1(self,request):
obj = self.get_queryset()
return Response("get-test1")