|
## 1 路由
# 1 在urls.py中配置
path('books4/', views.Book4View.as_view()),
re_path('books4/(?P<pk>\d+)', views.Book4DetailView.as_view()),
# 2 一旦视图类,继承了ViewSetMixin,路由
path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #当路径匹配,又是get请求,会执行Book5View的list方法
re_path('books5/(?P<pk>\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),
# 3 继承自视图类,ModelViewSet的路由写法(自动生成路由)
-urls.py
# 第一步:导入routers模块
from rest_framework import routers
# 第二步:有两个类,实例化得到对象
# routers.DefaultRouter 生成的路由更多
# routers.SimpleRouter
router=routers.DefaultRouter()
SimpleRouter会生成两条路由
<URLPattern '^books/$' [name='book-list']>,
<URLPattern '^books/(?P<pk>[^/.]+)/$'[name='book-detail']>
DefaultRouter生成6条路由
^books/$ [name='book-list']
^books/(?P<pk>[^/.]+)/$ [name='book-detail'] 这两条跟simple一样
^$ [name='api-root'] 根,根路径会显示出所有可以访问的地址
^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']
^books\.(?P<format>[a-z0-9]+)/?$ [name='book-list'] http://127.0.0.1:8000/books.json
^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail'] http://127.0.0.1:8000/books/1.json
-
# 第三步:注册
# router.register('前缀','继承自ModelViewSet视图类','别名')
router.register('books',views.BookViewSet) # 不要加斜杠了
# 第四步
# router.urls # 自动生成的路由,加入到原路由中
# print(router.urls)
# urlpatterns+=router.urls[列表相加,也可以用for循环就是比较麻烦,要for循环两次],[字典相加用update方法]
'''
-views.py
from rest_framework.viewsets import ModelViewSet
from app01.models import Book
from app01.ser import BookSerializer
class BookViewSet(ModelViewSet):
queryset =Book.objects
serializer_class = BookSerializer
### 1.1 action的使用
# action干什么用?为了给继承自ModelViewSet的视图类中定义的函数也添加路由
# 使用
class BookViewSet(ModelViewSet):
queryset =Book.objects.all()
serializer_class = BookSerializer
# methods第一个参数,传一个列表,列表中放请求方式,
# ^books/get_1/$ [name='book-get-1'] 当向这个地址发送get请求,会执行下面的函数
# detail:布尔类型 如果是True
#^books/(?P<pk>[^/.]+)/get_1/$ [name='book-get-1']
@action(methods=['GET','POST'],detail=True)
def get_1(self,request,pk):
print(pk)
book=self.get_queryset()[:2] # 从0开始截取一条
ser=self.get_serializer(book,many=True)
return Response(ser.data)
# 装饰器,放在被装饰的函数上方,method:请求方式,detail:是否带pk
### 2.2 认证的源码分析
#1 APIVIew----》dispatch方法---》self.initial(request, *args, **kwargs)包装成新的reqeust---->有认证,权限,频率
#2 只读认证源码: self.perform_authentication(request) 这个目前还在APIview类中,找还是先从自己的视图类中找
#3 self.perform_authentication(request)就一句话:request.user,需要去drf的Request对象中找user属性(方法)
#4 Request类中的user方法,刚开始来,没有_user,走 self._authenticate(),通过drf的Request中发现.user有@name.setattr这个是放值,我们要用取值的方法
def user(self):
if no hasattr(self,'_user'):如果request没有_user走下面判断
with wrap_attributeerrors():
self._authenticate() 走Request的这个方法
return self._user
#5 核心,就是Request类的 _authenticate(self):
def _authenticate(self):
# self.authenticators配置的一堆认证类产生的认证类对象组成的 list
# self.authenticators 你在视图类中配置的一个个的认证类:authentication_classes=[认证类1,认证类,对象的列表
for authenticator in self.authenticators:
[# self.authenticators---》先去Request中找,发现在__init__中,当作参数传进来的,说明在初始化的时候被传进来的--》上一层dispatch中,发现在APIview的里面中有这个方法get_authenticators方法,是一个列表生成式[对象1,对象]
try:
# 认证器(对象)调用认证方法authenticate(认证类对象self, request请求对象)
# 返回值:登陆的用户与认证的信息组成的 tuple
# 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败
user_auth_tuple = authenticator.authenticate(self) # [注意这self是Request对象所以写authenticate时会把request也会闯过了,认证对象调用自己的authenticate方法也会把认证类自动传进来]
except exceptions.APIException:
self._not_authenticated()
raise
# 返回值的处理
if user_auth_tuple is not None:
self._authenticator = authenticator
# 如何有返回值,就将 登陆用户 与 登陆认证 分别保存到 request.user、request.auth
self.user, self.auth = user_auth_tuple
return
# 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登陆用户 与 登陆认证信息,代表游客
self._not_authenticated()
### 2.3 认证组件的使用
# 写一个认证类 app_auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
# 认证逻辑,如果认证通过,返回两个值
#如果认证失败,抛出AuthenticationFailed异常
token=request.GET.get('token')
if token:
user_token=UserToken.objects.filter(token=token).first()
# 认证通过
if user_token:
return user_token.user,token[user_token.user这个就是为什么request.user可以拿到当前用户的对象,.user跨表到User用户对象里面去了]
else:
raise AuthenticationFailed('认证失败')
else:
raise AuthenticationFailed('请求地址中需要携带token')
# 可以有多个认证,从左到右依次执行
# 全局使用,在setting.py中配置
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}
# 局部使用,在视图类上写
authentication_classes=[MyAuthentication]
# 局部禁用
authentication_classes=[]
|
|