drf在serializer里获取当前用户–加入权限认证
-
案列—用户收藏
-
model
class UserFav(models.Model): """ 用户收藏 """ user = models.ForeignKey(UserProfile, verbose_name="用户") goods = models.ForeignKey(Goods, verbose_name="商品") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间") class Meta: db_table = "user_fav" verbose_name = "用户收藏" verbose_name_plural = verbose_name # unique_together 这里面设置的字段作为一个联合唯一索引 # 如果存在的数据重复数据库会抛出一条异常 # 在makemigrations时如果表里面有重复的数据, 那么直接makemigrations失败 # 建议清空表在makemigrations unique_together = ("user", "goods") def __str__(self): return self.user.name
-
permission
from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): """ 对象级权限,只允许对象的所有者编辑它。 假设模型实例有一个“user”属性。 """ # 它会来检测我们的obj, 这个obj就是我们从数据库取出来的obj def has_object_permission(self, request, view, obj): # 读取权限允许任何请求, # 所以我们总是允许GET、HEAD或OPTIONS请求。 if request.method in permissions.SAFE_METHODS: return True # 否则我们就判断, 当前数据的用户名是否跟当前用户一致 # 实例必须有一个名为“user”的属性。 # model实例obj return obj.user == request.user
-
views
from rest_framework import mixins from rest_framework import viewsets # IsAuthenticated判断用户是否登入 from rest_framework.permissions import IsAuthenticated # jsonwebtoken # 将用户post过来的token作为一个验证, 验证完成之后, 将他的user取出来 from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.authentication import SessionAuthentication from .models import UserFav from .serializers import UserFavSerializer from utils.permissions import IsOwnerOrReadOnly class UserFavViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): """ 用户收藏 """ # queryset = UserFav.objects.all() # IsAuthenticated指定权限, 用户登入才能访问 # IsOwnerOrReadOnly总是允许GET、HEAD或OPTIONS请求, 其他请求判断当前操作的数据它的user是否为当前用户 permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) serializer_class = UserFavSerializer # json token的验证 局部大于全局, 就算你在全局设置过, 但是你只要在这里加上authentication_classes 就会替换全局设置 authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication) # 指定过滤条件, 以后查询只能根据goods_id来查 # 这里的过滤集是下面已经, 过滤了的queryset, # 所以你在这里过滤的商品, 还是当前用户的 lookup_field = "goods_id" # 这里用了get_queryset来指定queryset 那么我们上面的query_set可以省略不写, 但是前提是在注册路由是需要加个base_name def get_queryset(self): # self.request.user 当前用户 return UserFav.objects.filter(user=self.request.user)
-
serializer–model加了 unique_together = (“user”, “goods”)这里是可以不同加validators的, 两个是一样的效果, 不过加了validators可以自定义报错消息
from rest_framework import serializers from rest_framework.validators import UniqueTogetherValidator from .models import UserFav class UserFavSerializer(serializers.ModelSerializer): # 获取当前用户 user = serializers.HiddenField( default=serializers.CurrentUserDefault() ) class Meta: model = UserFav # 把user和goods作为联合索引 # 数据库如果重复, 抛出异常 # 由于UniqueTogetherValidator是对多字段操作, 所以自能写在Meta下, Meta上是对单字段操作的 validators = [ UniqueTogetherValidator( queryset=UserFav.objects.all(), fields=['user', 'goods'], message="已经收藏" ) ] fields = ( "user", "goods", # 因为我们添加了删除的功能, 所以一定要把商品的id返回回来 "id" )
-
url
from rest_framework.routers import DefaultRouter from user_operation.views import UserFavViewSet router = DefaultRouter() # 用户收藏 router.register(r"userfavs", UserFavViewSet, base_name="userfavs") urlpatterns = [ # 自动生成url url(r"^", include(router.urls)), ]
-
效果图
-
添加
-
重复添加
-
删除
-
获取所有当前用户收藏–id为3的是别的用户收藏
-
获取单个–因为我们添加了lookup_field, 我们不能再根据数据库表id查, 只能根据指定的字段goods_id来查
-
登入问题
-
官网介绍