rest_framework路由及认证组件

1 路由

1.1自动生成路由(视图类需要继承ViewSetMixin类)

urlpatterns = [
path('api/book/',views.BookView.as_view({'get':'list','post':'create'})),
re_path(r'^api/book/(?P<pk>\d+)',views.BookView.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
]

以上是我们正常写路由的方式,以book模型类为例,增删改查的操作需要用两个路由才能实现,通过rest_framework可以自动生成以上的路由,可以提高我们的效率




一下为自动生成路由的步骤

# url.py
from rest_framework.routers import SimpleRouter,DefaultRouter 
router=SimpleRouter() # routers.DefaultRouter 生成的路由更多(但我们基本用不用着)
router.register('api/book',views.BookView) # 注册register('前缀','继承自ModelViewSet视图类','别名')
urlpatterns = [

]
urlpatterns+=router.urls # 生成的路由放在urls中

以上生成的路由和我们自己写的连个路由相同

1.2 action的使用

action可以给继承ModelViewSet的视图类中定义的函数也添加路由,需要配置路由自动生成,就是上面的步骤
导入:from rest_framework.decorators import action

# view.py
class BookView(ModelViewSet):
	queryset = Book.objects
	serializer_class = BookSerializer

	@action(methods=['GET','POST'],detail=False) # methods设置请求的方式,detail如果设置成True会生成^books/(?P<pk>[^/.]+)/get_1/$ [name='book-get-1'],方法要改成get_all_book(self,request,pk)
	def get_all_book(self,request):
		return Response({'status':'ok'})

action总结:装饰器,放在被装饰的函数上方,method:请求方式,detail:是否带pk

2认证

2.1认证的写法

1 写一个类,继承BaseAuthentication,重写authenticate,认证的逻辑写在里面,认证通过,返回两个值,一个值最终给了Requet对象的user,认证失败,抛异常:APIException或者AuthenticationFailed
# models.py
class Book(models.Model):
	name=models.CharField(max_length=32)
	price=models.CharField(max_length=32)

class UserInfo(models.Model):
	name=models.CharField(max_length=32)
	password=models.CharField(max_length=32)
	user_type=models.IntegerField(choices=((1,'超级用户'),(2,'一般用户'),(3,'限制用户')))

class UserSession(models.Model):
	session=models.CharField(max_length=32)
	user=models.OneToOneField('UserInfo',on_delete=models.CASCADE)
	
	
	
# app_auth.py
from rest_framework.authentication import BaseAuthentication
from app01.models import UserSession
from rest_framework.exceptions import AuthenticationFailed
class Myauthentication(BaseAuthentication):
	def authenticate(self, request):
		session=request.GET.get('session')
		if session:
			user_session=UserSession.objects.filter(session=session).first()
			if user_session:
				return user_session.user,session
			raise AuthenticationFailed('认证失败')
		raise AuthenticationFailed('请求地址需要携带session')

		
		
		
# url.py
from django.urls import path, re_path
from rest_framework.routers import SimpleRouter
from app01 import views

router = SimpleRouter()
router.register('api/book', views.BookView)

urlpatterns = [
	path('login/', views.LoginView.as_view())
]
urlpatterns += router.urls



# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from app01.models import UserInfo,UserSession,Book
from app01.ser import BookSerializer
from app01.app_auth import Myauthentication
from uuid import uuid4

class LoginView(APIView):
	authentication_classes = []
	def post(self,request):
		user=UserInfo.objects.filter(**request.data).first()
		if user:
			session=uuid4()
			UserSession.objects.update_or_create(defaults={'session':session},user=user)
			return Response({'status':200,'msg':'登录成功','session':session})
		return Response({'status':101,'msg':'用户名或密码错误'})



class BookView(ModelViewSet):
	queryset = Book.objects.all()
	serializer_class = BookSerializer
	authentication_classes = [Myauthentication] # 只有通过认证才能访问BookView类视图函数

2.2 局部认证和全局认证

局部认证:

在上述BookView视图类中使用的时局部认证,只有在此视图类中的视图函数被执行前才会先认证,上述LoginView视图类不需要先经过认证
局部认证的使用方法就是在需要认证的视图类中定义authentication_classes = [认证1,认证2],认证会从左到右依次执行

全局认证:

全局认证只需要在setting中进行配置即可

REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.Myauthentication",]
}

那么,如果我们不想只让其中某个视图类不需要进过校验如我们上述例子的LoginView视图类,只需要在视图类中将authentication_classes = []即可

class LoginView(APIView):
		authentication_classes = [] # 将此参数定义为空列表,查找此参数时会先从此查找
		def post(self,request):
			user=UserInfo.objects.filter(**request.data).first()
			if user:
				session=uuid4()
				UserSession.objects.update_or_create(defaults={'session':session},user=user)
				return Response({'status':200,'msg':'登录成功','session':session})
			return Response({'status':101,'msg':'用户名或密码错误'})
posted @ 2022-07-19 13:16  mress  阅读(74)  评论(0)    收藏  举报