本代码完成的功能是:
1.根据token判断用户登录状态,然后提示用户是否登陆,
2.用户登录后,根据用户类型判断用户是否有权限查看资料
使用rest_framework一定要在配置文件设置先设置 'rest_framework',
INSTALLED_APPS = ( ... 'rest_framework', )
Step1:数据库模型类models.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Django Library from django.db import models class User(models.Model): """ 存储用户信息 """ user_name = models.CharField(max_length=32) password = models.EmailField(max_length=32) user_type_entry = ( (1, 'Delux'), (2, 'SVIP'), (3, "VVIP") ) user_type = models.IntegerField(choices=user_type_entry) def __str__(self): return self.user_name class UserToken(models.Model): """ 存储用户登录的token值 """ user = models.OneToOneField("User", on_delete=models.CASCADE) token = models.CharField(max_length=128) class Book(models.Model): """ 图书信息表 """ nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) # 外键字段 publish = models.ForeignKey(to="Publish", related_name="book", related_query_name="book_query", on_delete=models.CASCADE) # 多对多字段 authors = models.ManyToManyField(to="Author") def __str__(self): return self.title class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name
Step2:视图类views.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Django from django.http import JsonResponse # Third-party Library from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet # Custom Library from app01.service import get_token from app01.service.authentication_class import UserAuth1 from app01.service.permission_class import UserPerm from app01.service.serializer_class import BookSerializer from .models import User, UserToken, Book # 图书视图类 class BookView(ModelViewSet): # 用户认证 authentication_classes = [UserAuth1] # 权限认证 permission_classes = [UserPerm] # 获取图书列表 queryset = Book.objects.all() # 序列化类 serializer_class = BookSerializer # 用户视图类 class UserView(APIView): def post(self, request): response = dict() try: user_name = request.data['username'] password = request.data['password'] user_obj = User.objects.filter(user_name=user_name, password=password).first() if user_obj: access_token = get_token.generate_token() UserToken.objects.update_or_create(user=user_obj, defaults={"token": access_token}) response["status_code"] = 200 response["status_message"] = "登录成功" response["access_token"] = access_token response["user_role"] = user_obj.get_user_type_display() else: response["status_code"] = 201 response["status_message"] = "登录失败,用户名或密码错误" except Exception as e: response["status_code"] = 202 response["status_message"] = str(e) return JsonResponse(response) # Token值视图类 class UserTokenView(APIView): def get(self): tokens = UserToken.objects.all()
Step3:认证组件authentication_class.py
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import APIException from app01.models import UserToken # 方法1:定义认证类 class UserAuth1(BaseAuthentication):
def authenticate_header(self, request):
pass
# 所有的认证逻辑都在authenticate def authenticate(self, request): user_token = request.query_params.get("token") try: token = UserToken.objects.get(token=user_token) # 后面权限会用到 return token.user, token.token except Exception: raise APIException("认证失败,用户名与密码不符!") # 方法2:定义认证类 class UserAuth2(BaseAuthentication): # 所有的认证逻辑都在authenticate def authenticate(self, request): user_token = request.query_params.get("token") try: token = UserToken.objects.get(token=user_token) # 后面权限会用到 return token.user, token.token except Exception: raise APIException("认证失败,用户名与密码不符!")
Step4-1:权限组件permission_class.py
#!/usr/bin/env python # -*- coding:utf-8 -*- class UserPerm(): # 自定义错误信息 message = "您没有查看该数据的权限!" def has_permission(self, request, view): # 判断逻辑都在这里 # 本次是根据用户user_type==3判断有 if request.user.user_type == 2: return True return False
Step4-2:获取token值get_token.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # 生成一个随机字符串 import uuid def generate_token(): random_str = str(uuid.uuid4()).replace('-', '') return random_str
Step5:序列化组件serializer_class.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Third-party Library from rest_framework import serializers # Custome Library from app01.models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book # 这里展示的字段必须是数据库中有的,或者是额外字段,或者多对多字段 fields = ('title', 'price', 'publish', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { 'publish': {'write_only': True}, # 这里的authors是models模型中的字段,因为是多对多,我们不想直接让其显示,所以这里限制只写 'authors':{'write_only': True}, } # 额外拓展字段,出版社名字 publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') # 额外拓展字段,出版社城市 publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') # 获取多对多字段,这类的author_list与fields字段author_list一致 author_list = serializers.SerializerMethodField() # get_后面与上面的author_list要保持一致才可以 def get_author_list(self, book_obj): # 拿到queryset开始循环 [{}, {}, {}, {}] authors = list() # 循环每个作者对象,获取作者名字,添加到列表authors for author in book_obj.authors.all(): authors.append(author.name) # 返回作者列表 return authors
Step6:路由urls.py
from django.contrib import admin from django.urls import path, re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path('user/', views.UserView.as_view()), re_path('books/', views.BookView.as_view({'get': 'list'})) ]