drf路由自动生成与登录认证
路由自动生成
# 首先我们第一步需要将SimpleRouter, DefaultRouter进行导入,DefaultRouter的功能只是比SimpleRouter多一条根路径,显示所有注册过的路由
from rest_framework.routers import SimpleRouter, DefaultRouter
# 第二步需要将router进行实例化处理
# router = SimpleRouter()
router = DefaultRouter()
# 第三步需要注册
router.register('books', views.BookView, 'books')
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('books/', views.BookView, 'book'),
# path('user', views.UserView, 'user'),
path('', include(router.urls)),
]
# 第四步,将路由添加到urlpatterns中两种方式
# urlpatterns += router.urls
# 方式二:
# path('', include(router.urls)),
action装饰器
from rest_framework.response import Response
from rest_framework.decorators import action
# 我们在自动生成的接口中只能有五大扩展和九大子类,没有其他的那么我们如果也想要,那么就需要使用action这个装饰器做映射处理
class UserView(ViewSet):
# action中的形参第一个是请求方式,第二个是detail默认是False,控制生成的路由是否有pk值,
# 第三个url_path是控制路由后面跟的是什么可以不填,如果不填的话那么就默认为你的函数名,
# 第四个url_name是控制重命名,用于反向解析
@action(methods=['GET','POST'], detail=False, url_path='login', url_name='login')
def login(self, request, pk):
# print(pk)
return Response('ok ')
on_delete参数的各个值的含义
on_delete参数的各个值的含义:
1.on_delete=models.None, # 删除关联表中的数据时,当前表与其关联的field的行为
2.on_delete=models.CASCADE, # 级联删除,删除关联关系,与之关联也删除
3.on-delete=models.DO_NOTHING, # 删除管来呢数据,什么也不做
4.on_delete=models.PRPTECT, # 保护模式,删除关联数据,引发错误protectedError
5.models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
6.on_delete=models.SET_NULL, # 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。当Manufacturer对象删除时,它对应的Car对象的manufacturer字段会置空,前提是null=True
7.models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
8.on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
9.on_delete=models.SET, # 删除关联数据,自定义一个值,该值当然只能是对应的实体了
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
登录接口编写
models.py
用户表创建
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
def __str__(self):
return self.username
token表创建
# 为了检验用户是否登录我们需要使用token标记,有了token我们就相当于在浏览器使用session一样
class UserToken(models.Model):
user = models.OneToOneField(to='User', on_delete=models.CASCADE)
token = models.CharField(max_length=32, null=True) # 用来区分用户是否为登录状态,
# 如果登录了那么token有值,如果没有登录那么token为空,如果登录多次每次的token值不同,以最后一个token为基准
views.py
class UserView(ViewSet):
authentication_classes = []
@action(methods=['POST','GET'], detail=False, url_path='login')
def login(self, request):
username = request.data.get('username')
password = request.data.get('password')
user = User.objects.filter(username=username, password=password).first()
if user:# 如果有值那么登录成功,直接自动生成一个token存入UserToken表中
token = str(uuid.uuid4()) # 使用uuid也就是随机生成永不重复的字符串,我们图方便就使用uuid4这个不需要条件的直接生成
# 其中有uuid1, uuid3,uuid5都是需要条件才可以生成随机字符串
# 将随机字符串存入UserToken中,如果有值则重置为最后使用的token,如果没有那么就是新增,我们为了
# 方便所以直接使用update_or_create直接添加或者修改
UserToken.objects.update_or_create(defaults={'token': token}, user=user) # 使用user
# 去UserToken中查找数据,如果能查到,defaults的数据更新,如果查不到,直接通过user和defaults的数据新增即可
return Response({'code':100, 'msg':'登录成功'})
else:
return Response({'code':101, 'msg': '用户名或密码错误'})
urls.py
# 首先我们第一步需要将SimpleRouter, DefaultRouter进行导入,DefaultRouter的功能只是比SimpleRouter多一条根路径,显示所有注册过的路由
from rest_framework.routers import SimpleRouter, DefaultRouter
# 第二步需要将router进行实例化处理
# router = SimpleRouter()
router = DefaultRouter()
# 第三步需要注册
router.register('user', views.UserView, 'user')
urlpatterns = [
path('admin/', admin.site.urls),
# 第四步,将路由添加到urlpatterns中两种方式
path('', include(router.urls)),
]
认证类
from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 检验用户是否等登录,也就是是否携带token,如果没有携带那么就是没有登录,带了那么就是已经登录,那么就返回两个值
# 我们携带token的话有多重选择方式,一在请求头中存储(不太安全容易被获取),二是存放到青丘体中
token = request.GET.get('token') # 获取token
# 通过获取的token来查询token是否在表中有记录
user_token = UserToken.objects.filter(token=token).first()
# 如果有那么校验通过,如果没有则返回还没有登录
if user_token:
return user_token.user,token # 返回两个值,一个是登录用户,另一个则是token
else:
# 在这边返回的报错信息使用AuthenticationFailed返回
raise AuthenticationFailed('您没有登录')
认证
1.我们有些功能需要等领域后才可以访问所以我们就需要使用认证的方式来校验是否登录也就是我们刚刚写的认证类,token
2.认证类
2.1 写一个认证类,需要继承BaseAuthentication
2.2 重写authenticate方法,在内部做认证
2.3 如果认证通过,返回2个值
2.4 认证不通过抛AuthenticationFailed异常
2.5 认证通过则返回两个值,
2.6 如果想让某个视图类登录之后才可以访问,那么就需要配置
方法一:
class BookView(ModelViewSet):
authentication_classes = [LoginAuth,]
serializer_class = BookSerializer
queryset = Book.objects.all()
方法二:
REST_FRAMEWORK={'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.LoginAuth',]
}
使用了全局配置那么如果某一个不想要登录才可以访问那么就需要提前写好不调用
class UserView(ViewSet):
authentication_classes = []
练习
五扩展views.py
from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \
ListModelMixin
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
authentication_classes = [LoginAuth, ]
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
authentication_classes = [LoginAuth, ]
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin):
authentication_classes = []
queryset = Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class PublishDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
authentication_classes = []
queryset = Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
五扩展urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
path('publish/', views.PublishView.as_view()),
path('publish/<int:pk>/', views.PublishDetailView.as_view()),
]
九子类视图集views.py
from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, DestroyAPIView, UpdateAPIView
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView,
RetrieveUpdateAPIView
class BookView1(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookView2(CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookView3(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView1(RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView2(DestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView3(UpdateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView4(RetrieveDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView5(RetrieveUpdateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView6(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishView1(ListAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishView2(CreateAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishView3(ListCreateAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishDetailView1(RetrieveAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishDetailView2(DestroyAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishDetailView3(UpdateAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishDetailView4(RetrieveDestroyAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishDetailView5(RetrieveUpdateAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
class PublishDetailView6(RetrieveUpdateDestroyAPIView):
authentication_classes = []
queryset = Book.objects.all()
serializer_class = BookSerializer
九子类视图集urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView1.as_view()),
path('books/', views.BookView2.as_view()),
path('books/', views.BookView3.as_view()),
path('books/<int:pk>/', views.BookDetailView1.as_view()),
path('books/<int:pk>/', views.BookDetailView2.as_view()),
path('books/<int:pk>/', views.BookDetailView3.as_view()),
path('books/<int:pk>/', views.BookDetailView4.as_view()),
path('books/<int:pk>/', views.BookDetailView5.as_view()),
path('books/<int:pk>/', views.BookDetailView6.as_view()),
path('publish/', views.PublishView1.as_view()),
path('publish/', views.PublishView2.as_view()),
path('publish/', views.PublishView3.as_view()),
path('publish/<int:pk>/', views.PublishDetailView1.as_view()),
path('publish/<int:pk>/', views.PublishDetailView2.as_view()),
path('publish/<int:pk>/', views.PublishDetailView3.as_view()),
path('publish/<int:pk>/', views.PublishDetailView4.as_view()),
path('publish/<int:pk>/', views.PublishDetailView5.as_view()),
path('publish/<int:pk>/', views.PublishDetailView6.as_view()),
]