内容提要:
详情页、校验是否为当前用户、配置联合唯一索引、drf的权限校验。
《Python前后端分离开发Vue+Django REST framework实战》作者bobby
——学习来源
第八章商品详情页
8.1详情页实现使用mixins.RetrieveModelMixin,就能立即实现商品详情页的功能。
如果商品详情的某个字段是外键,具有一对多的关系,则在serializers.py中,替换外键的配置即可。
from rest_framework import serializers
from goods.models import Goods,GoodsImage
class GoodsImageSerializer(serializers.ModelSerializer):
class Meta:
model = GoodsImage
fields = ("image",)
class GoodsSerializer(serializers.ModelSerializer):
category = GoodsCategorySerializer()
images = GoodsImageSerializer(many=True) # GoodsImage的外键名称是images
class Meta:
model = Goods
# fields = ('name','click_num','id') # 取出部分字段
fields = "__all__"
8.2热销商品实现
在filtes.py中商品过滤类添加is_hot过滤条件即可。
import django_filters
from .models import Goods
class GoodsFilter(django_filters.rest_framework.FilterSet):
...省略...
class Meta:
model = Goods
fields = ['price_min','price_max','name','is_hot'] # 把过滤条件添加进来
8.3商品收藏实现
serializers获取当前用户
官方文档:https://www.django-rest-framework.org/api-guide/validators/#currentuserdefault
如果想获取当前用户,可以使用以下方式。
from rest_framework import serializers
from .models import UserFav
class UserFavSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
) # 字段是当前用户
class Meta:
model = UserFav
fields = ("user", "goods","id")
删除收藏
rest_framework使用的rest方式进行增删改查,通过DELETE方法,即可完成删除。
配置联合唯一索引
在实际场景中,单个字段可以重复,但是某两个字段(例如收藏的user和goods)作为一个集合时不允许重复。可以使用以下两种方法解决该问题。
方法一:设置models联合唯一索引
该方法需要修改models并migrate,将数据库的两个字段作为联合唯一索引)。
from datetime import datetime
from django.db import models
from django.contrib.auth import get_user_model
from goods.models import Goods
User = get_user_model()
class UserFav(models.Model):
"""用户收藏"""
user = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name="用户")
goods = models.ForeignKey(Goods,on_delete=models.CASCADE,verbose_name="商品")
add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")
class Meta:
verbose_name = "用户收藏"
verbose_name_plural = verbose_name
unique_together = ("user", "goods") # 联合唯一索引
def __str__(self):
return self.user.name
方法二:serializers中配置Validators
官方文档:https://www.django-rest-framework.org/api-guide/validators/#uniquetogethervalidator
在serializers.py中添加联合唯一索引。
from rest_framework import serializers
from .models import UserFav
from rest_framework.validators import UniqueTogetherValidator
class UserFavSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
class Meta:
model = UserFav
validators = [
UniqueTogetherValidator(
queryset=UserFav.objects.all(),
fields=['user', 'goods'],
message="已经收藏"
)
] # 联合唯一索引,无法保存两个字段同时重复的记录
fields = ("user", "goods","id")
8.4drf的权限验证
在访问接口时,需要对收藏列表、收藏和取消收藏做单独的权限控制。
官方文档:https://www.django-rest-framework.org/api-guide/permissions/#examples
编写自定义权限校验的工具类。
# utils/permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""方法的权限校验"""
def has_object_permission(self, request, view, obj):
# 如果是安全的方法则返回True
if request.method in permissions.SAFE_METHODS:
return True
# 如果不是安全的方法,则判断是否为当前用户
return obj.user == request.user
在views中引用权限校验。
from rest_framework import viewsets
from rest_framework import mixins
from .models import UserFav
from .serializers import UserFavSerializer
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
class UserFavViewset(mixins.CreateModelMixin, mixins.DestroyModelMixin,viewsets.GenericViewSet):
"""用户收藏功能"""
permission_classes = (IsAuthenticated,IsOwnerOrReadOnly) # IsAuthenticated做了登录校验,IsOwnerOrReadOnly是自定义的权限校验
serializer_class = UserFavSerializer
def get_queryset(self):
return UserFav.objects.filter(user=self.request.user)
8.5更改单个记录的查询字段
使用mixins.RetrieveModelMixin时,默认查询是根据数据表准的id进行查找。如果想更改查找的字段,可以通过设置lookup_field来实现。
# views.py
from rest_framework import viewsets
from rest_framework import mixins
from .models import UserFav
from .serializers import UserFavSerializer
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin,viewsets.GenericViewSet):
"""用户收藏功能"""
permission_classes = (IsAuthenticated,IsOwnerOrReadOnly)
serializer_class = UserFavSerializer
lookup_field = "goods_id"
def get_queryset(self):
return UserFav.objects.filter(user=self.request.user)