drf的路由组件
# 快速实现接口
models.py
from django.db import models
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
publish = models.ForeignKey(to=Publish, on_delete=models.CASCADE)
"""
迁移数据库,通过各自路由的5个接口添加的数据,当然也可以手动添加.
1,南京出版社,南京
2,东京出版社,东京
1,三国演义,11,1
2,红楼梦,22,2
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
serializer.py
from rest_framework import serializers
from . import models
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
class PublishSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publish
fields = '__all__'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
views.py
from rest_framework.viewsets import ModelViewSet
from .models import Book, Publish
from .serializer import BookSerializer, PublishSerializer
# -- 实现图书的五个接口
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# -- 实现出版社的五个接口
class PublishView(ModelViewSet):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
path('publish/', views.PublishView.as_view({'get': 'list', 'post': 'create'})),
path('publish/<int:pk>', views.PublishView.as_view({'get': 'retrieve',
'put': 'update',
'delete': 'destroy'})),
]
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 自动生成路由
一共要经历四步!!
from django.contrib import admin
from django.urls import path, include
from app01 import views
# -- step1:导入
from rest_framework.routers import DefaultRouter, SimpleRouter
# -- step2:实例化得到router对象
# SimpleRouter和DefaultRouter用哪个都行.它两用法一致,功能几乎一样
router = SimpleRouter()
# router = DefaultRouter() # -- 它自动生成的路由多一条,多个根路径
# -- step3:注册视图集
# - 参数一:路径前缀
# - 参数二:视图类
# (★★★ 该视图类必须继承ViewSet类或其子类,也就是说视图类继承的父类以及父类的父亲直到object
# 只要有ViewSetMixin + APIView就可以 因为ViewSet = ViewSetMixin + APIView)
# - 参数三:别名(反向解析的时候使用 几乎不用)
router.register('books', views.BookView, basename='books')
router.register('publish', views.PublishView, basename='publish')
# 查看注册视图集后生成的路由
print(router.urls)
# -- step4:将自动生成的路由列表添加到总路由中,有两种方式!
# - 方式一: 使用路由分发的方式添加! include.
urlpatterns = [
path('admin/', admin.site.urls),
# -- 自动生成以下几条路由!!
# path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
# path('books/<int:pk>', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
# path('publish/', views.PublishView.as_view({'get': 'list', 'post': 'create'})),
# path('publish/<int:pk>', views.PublishView.as_view({'get': 'retrieve',
# 'put': 'update',
# 'delete': 'destroy'})),
path('', include(router.urls))
]
# - 方式二:
# 两列表相加,就相当于extend!
# urlpatterns += router.urls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# action的使用
前面我们成功生成了路由地址[增/删/改/查一条/查多条的功能]
若要给自定义方法生成路由, 则需要进行action动作的声明!
以action装饰器装饰的方法名会作为action动作名, 与list、retrieve等同..
urls.py
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter, DefaultRouter
router = SimpleRouter()
router.register('books', views.BookView, basename='books')
router.register('publish', views.PublishView, basename='publish')
router.register('test', views.TestView, basename='test')
urlpatterns = [
path('admin/', admin.site.urls),
# -- 手动自己写!
# 思考一个问题,若不手动自己写,那自动生成的,如何知道 as_view({}) 字典里的对应关系呢?
# 也就是不知道用什么请求get/post/put.. 触发login方法.
# 解决方案:在视图类里使用action装饰器!!
# path('test/', views.TestView.as_view({'get': 'login'})),
]
urlpatterns += router.urls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
views.py
from rest_framework.viewsets import ModelViewSet
from .models import Book, Publish
from .serializer import BookSerializer, PublishSerializer
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
# -- 实现图书的五个接口
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# -- 实现出版社的五个接口
class PublishView(ModelViewSet):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
# -- 回顾下:继承了ViewSet以后,里面的方法可以随便命名!
class TestView(ViewSet):
"""action的参数
methods -- 做一个映射,也就是http的请求方式会映射当前方法
这里get和post请求都会触发login
相当于 path('test/', views.TestView.as_view({'get': 'login','post': 'login'})),
detail -- True或False
False - /test/login 类似于获取所有的视图类 多条
True - /test/pk/login 类似于获取详情的视图类 单条
url_path -- 访问的路径“可写正则”,可以不写, ★若不写,默认值就是方法名,默认访问的路径是方法名!!
-- 若detail=False
若 在路由层router.register('test', ..) 以及 这里的url_path='login'
那么 /test/login 路径下的get或post请求就会触发login方法的执行!
Ps:若使用的是路由分发的方式将自动生成的路由列表添加到总路由中.
eg: - path('wow', include(router.urls)) 、
- router.register('test', ..)、
- url_path='login'
那么访问的路径应该是 /wow/test/login
-- 若detail=True
若 在路由层router.register('test', ..) 以及 这里的url_path='login'
那么 /test/pk/login 路径下的get或post请求就会触发login方法的执行!
Ps:若使用的是路由分发的方式将自动生成的路由列表添加到总路由中.
eg: - path('wow', include(router.urls)) 、
- router.register('test', ..)、
- url_path='login'
那么访问的路径应该是 /wow/test/pk/login
url_name -- 别名.(反向解析时用)
"""
# @action(methods=['GET', 'POST'], detail=False, url_path='login', url_name='login')
@action(methods=['GET', 'POST'], detail=False)
def login(self, request):
return Response('登陆成功!')
# @action(methods=['GET', 'PUT', 'DELETE'], detail=True)
# def login(self, request, pk):
# return Response('登陆成功!')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 扩展: .action
动态的替换掉方法使用的序列化类/切换序列化器
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from .models import Test
from .serializer import TestSerializer, OtherSerializer
# -- 视图类继承了GenericViewSet
# 视图类里可以有很多很多方法,不一定都要用BookSerializer这个序列化类来序列化!
# 所以我们可以重写get_serializer_class方法!!
class TestView(GenericViewSet):
queryset = Test.objects.all()
serializer_class = TestSerializer
def get_serializer_class(self):
# -- 当前视图类的对象中就有action属性,我们可以通过这个属性判断当前请求会执行哪个视图类中的方法!
# -- 动态的替换掉方法使用的序列化类
if self.action == 'login':
return OtherSerializer
else: # -- 否则使用原来的序列化类
# return super().get_serializer_class()
return self.serializer_class
@action(methods=['GET', 'POST'], detail=False)
def login(self, request):
return Response('登陆成功!')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26