Django里rest_framework的权限组件

权限组件

  1. 使用方式介绍

    • 定义一个权限类

      class UserPerm():
        	def has_permission(self, request, view):
            	pass
      
    • 指定权限验证的类

      class BookView(APIView):
        	# 指定认证类
          authentication_classes = [UserAuth]
        	# 指定权限验证的类
        	permission_classes = [UserPerm]
          
          queryset = BookInfo.objects.all()
          serializer = BookSerializer
      

案列

  • 导入模块

     from django.http import JsonResponse
     
     from rest_framework.views import APIView
     from rest_framework.viewsets import ModelViewSet
     from rest_framework.exceptions import APIException
    
  • url.py

    from django.urls import re_path
    from .views import UserView, BookView
    
    urlpatterns = [
        re_path(r"^books/$", BookView.as_view({
            "get": "list",
            "post": "create"
        })),
    
        re_path(r"^books/(?P<pk>\d+)/$", BookView.as_view({
            "get": "retrieve",
            "put": "update",
            "delete": "destroy"
        })),
    
        re_path(r"^user/$", UserView.as_view())
    ]
    
    
- model.py

  ```python
  from django.db import models
  
  from datetime import datetime
  # from django.contrib.auth.models import AbstractUser
  
  
  class UserInfo(models.Model):
      username = models.CharField(max_length=32, verbose_name="用户名")
      password = models.CharField(max_length=40, verbose_name="用户密码")
      user_type_entry = (
          (1, "Delux"),
          (2, "SVIP"),
          (3, "VVIP")
      )
      user_type = models.IntegerField(choices=user_type_entry)
  
      class Meta:
          db_table = "db_user_info"
          verbose_name = "用户信息"
          verbose_name_plural = verbose_name
  
      def get_user_type_display(self):
          return self.user_type_entry[self.user_type]
  
  
  class UserToken(models.Model):
      # OneToOneField一对一关系
      # on_delete=models.CASCADE 当UserInfo数据表里面的数据被删除后UserToken里面的数据也随着被删除
      user = models.OneToOneField("UserInfo", on_delete=models.CASCADE, verbose_name="一对一关系")
      token = models.CharField(max_length=128, verbose_name="token")
  
      class Meta:
          db_table = "db_user_token"
          verbose_name = "用户token"
          verbose_name_plural = verbose_name
  
  
  class AuthorInfo(models.Model):
      name = models.CharField(max_length=32, verbose_name="作者名称")
      age = models.IntegerField(verbose_name="作者年龄")
  
      class Meta:
          db_table = "db_author_info"
          verbose_name = "作者信息"
          verbose_name_plural = verbose_name
  
      def __str__(self):
          return self.name
  
  
  class PublishInfo(models.Model):
      name = models.CharField(max_length=32, verbose_name="出版社名称")
      city = models.CharField(max_length=32, verbose_name="出版社所在城市")
      email = models.EmailField(verbose_name="出版社邮箱")
  
      class Meta:
          db_table = "db_publish_info"
          verbose_name = "出版社信息"
          verbose_name_plural = verbose_name
  
      def __str__(self):
          return self.name
  
  
  class BookInfo(models.Model):
      title = models.CharField(max_length=32, verbose_name="书名")
      publishDate = models.DateField(default=datetime.now, verbose_name="出版日期")
  
      # max_digits小数位加整数位多少长度 decimal_places小数位长度为2
      price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="图书价格")
      publish = models.ForeignKey(PublishInfo, related_name="book", related_query_name="book_query", on_delete=models.CASCADE, verbose_name="出版社")
      # ManyToManyField多对多
      authors = models.ManyToManyField(AuthorInfo, verbose_name="图书作者")
  
      class Meta:
          db_table = "db_book_info"
          verbose_name = "图书信息"
          verbose_name_plural = verbose_name
  
      def __str__(self):
          return self.title
  
  ```

- 序列化类

  ```python
  from.models import BookInfo
  
  # 第一步: 导入模块
  from rest_framework import serializers
  
  from datetime import datetime
  
  
  class BookSerializer(serializers.ModelSerializer):
      class Meta:
          # 指定    要操作的模型类
          model = BookInfo
  
          # 指定序列化的字段
          fields = (
              "title",
              "price",
              "publishDate",
              "publish",
              "authors",
              "author_list",
              "publish_name",
              "publish_city"
          )
  
          # 指定那些字段是只写的
          # write_only只写的 (只写的 前端发送数据时要写它, 后端返回数据时没有它)
          extra_kwargs = {
              "publish": {"write_only": True},
              "authors": {"write_only": True}
          }
  
      # 自定义的字段
      # read_only只读的 (只读的 前端发送数据时不用写它, 后端返回数据时有它)
      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 = serializers.SerializerMethodField()
  
      def get_author_list(self, book_obj):
          # 拿到queryset开始循环 [ {}, {}, {}]
          authors = []
  
          for author in book_obj.authors.all():
              authors.append(author.name)
          return authors
  ```

- token值

  ```python
  import uuid
  
  def generate_token():
    	# 把uuid残生出来的值转换成字符串, 然后以-切割在以空链接
      random_str = str(uuid.uuid4()).replace("-", "")
      return random_str
  ```

  

- views.py

	 ```python
	from django.http import JsonResponse
	
	from rest_framework.views import APIView
	from rest_framework.viewsets import ModelViewSet
	from rest_framework.exceptions import APIException
	from rest_framework.authentication import BaseAuthentication
	
	from .models import BookInfo, PublishInfo, AuthorInfo, UserInfo, UserToken
	from .app_serializers import BookSerializer
	from .utils import get_token
	
	# 第一步: 定义认证类
	class UserAuth(BaseAuthentication):
	# 所有的逻辑都在authenticate上写
	def authenticate(self, request):
	    # 获取token值
	    user_token = request.GET.get("token", "")
	    if user_token:
	        try:
	            # 查询token值看有没有认证过的token
	            token = UserToken.objects.get(token=user_token)
	            # 后面权限会用到
	            # token.user.username赋值给了request.user, 可以去看源码
	
	            return token.user.username, token.token
	        except UserToken.DoesNotExist:
	            raise APIException("没有认证")
	    else:
	        raise APIException("没有认证")
	
	
	class UserPerm(object):
	 # 必须是message, 因为源码用的是message, 我们这里用message就是覆盖掉源码
	 # 所以返回为假时, 我们可以用message自定义你想返回给用户看到的信息
	 message = "您没有查看该数据的权限!"
	
	 # 这是对所有数据
	 # 这个has_permission也是重写的
	 # 用户有权限必须返回真, 用户没权限必须返回假  不懂看, 源码
	 def has_permission(self, request, view):
	     if request.user.user_type == 1:
	         # request.user 获取到 认证组件返回的用户对象
	         # type是用户表中的一个字段
	         # 这里如果等于3就代表该用户有看这个数据的权限, 返回能代表真的信息就行
	         return True
	     # 这里返回的东西必须需是能代表假, 因为用户没有这个权限, 所以不能等它看到数据
	     return False
	
	 # 这是对单条数据
	 def has_object_permission(self, request, view, obj):
	     if request.user.user_type == 1:
	     	# request.user 获取到 认证组件返回的用户对象
	         # type是用户表中的一个字段
	         # 这里如果等于3就代表该用户有看这个数据的权限, 返回能代表真的信息就行
	         return True
		 # 这里返回的东西必须需是能代表假, 因为用户没有这个权限, 所以不能等它看到数据
	     return False
	
	
	class BookView(ModelViewSet):
	# 第二步: 指定认证类 UserAuth
	authentication_classes = [UserAuth]
	# 指定权限类
	permission_classes = [UserPerm]
	queryset = BookInfo.objects.all()
	serializer_class = BookSerializer
	
	
	class UserView(APIView):
	
	def post(self, request):
	
	    response = dict()
	
	    # 定义需要的用户信息
	    fields = {"username", "password"}
	    # 定义一个用户信息字典
	    user_info = dict()
	
	    # fields.issubset表示 fields是request.data.keys()的子集就显示True, 相反False
	    if fields.issubset(set(request.data.keys())):
	        # username = request.data.get("username", "")
	        # password = request.data.get("password", "")
	        for key in fields:
	            user_info[key] = request.data[key]
	
	    if user_info:
	        # **user_info字典拆包 拆包成键值对, 而不是整个字典了 列 {"a":"bb"} 拆包成 a="bb"
	        user_instance = UserInfo.objects.filter(**user_info).first()
	
	        if user_instance is not None:
	            access_token = get_token.generate_token()
	
	            # 根据user=user_instance找到了直接更新, 把default的值复制给它
	            # 没有找到直接创建
	            # 意思就是有这个token更新token, 没有这个token创建一个token
	            UserToken.objects.update_or_create(user=user_instance, defaults={
	                "token": access_token
	            })
	
	            response["status_code"] = 200
	            response["status_message"] = "登入成功"
	            response["access_token"] = access_token
	            response["user_role"] = user_instance.get_user_type_display()
	        else:
	            response["status_code"] = 201
	            response["status_message"] = "登入失败, 用户名或密码错误"
	
	        return JsonResponse(response)
	    else:
	        return JsonResponse({"error": "参数不完整"})
	```
  1. 权限类源码
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只因为你而温柔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值