vue+django2.0.2-rest-framework 生鲜项目


 一、商品详情功能开发


 

上一章中已经完成了用户注册登录认证, 商品分类、商品列表页等功能,接下来我们完成商品的详情页功能。

 1、商品详情页很简单,首先,在goods/views.py中的GoodsListViewSet,添加继承:

mixins.RetrieveModelMixin:用于获取单个数据的列表页
class GoodsListViewSet(mixins.ListModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet):

因为商品详情中需要用到商品轮播图,而商品轮播图是关联着我们商品,我们在序列化商品时未序列化轮播图信息,因此需要序列化轮播图,好用于返回到api接口,让前端可以调用

首先,编写序列化商品详情页中的轮播图类:

class GoodsImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsImage
        fields = ("image", )

然后,在商品序列化的类中添加相关联的商品详情轮播图,进行序列化:

class GoodsSerializer(serializers.ModelSerializer):
    # 手动添加字段,如model中有则会覆盖字段。
    # 此为外键字段,实例化,会获取关联表的所有数据. 商品关联分类
    category = CategorySerializer()
    # 商品详情轮播图,轮播表关联商品表
    images = GoodsImageSerializer(many=True) # 新增
    class Meta:
        model = Goods
        fields = '__all__'

此时,浏览器访问:http://127.0.0.1:8000/goods/ ,或者访问http://127.0.0.1:8000/goods/id/ 时,就会发现数据中,也把轮播图相关的图片都展示出来了。


 

2、实现热卖商品功能

 只需要在goods/filter.py中,过滤器上添加:is_hot 字段便可以了:

filter/GoodsFilter类:

    class Meta:
        model = Goods
        fields = ['pricemin', 'pricemax','top_category','is_hot']

接着在后台设置热卖商品:in_hot设为True,前端热卖商品组件便会显示出热卖的商品了:

 


 二、用户操作相关功能(个人中心)

1、用户收藏功能

 用户收藏功能,与用户操作有关,相关代码操作在user_operation APP中进行,同时需要authenticate相关认证。

首先,未加权限前的相关操作:1)到user_operation APP中新建序列化py文件:serializers.py

# user_operation/serializers.py

from rest_framework import serializers
from user_operation.models import UserFav
from rest_framework.validators import UniqueTogetherValidator

class UserFavSerializer(serializers.ModelSerializer):
    # 获取当前登录的用户,并隐藏不展示到api接口中
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    class Meta:
        #UniqueTogetherValidator用于唯一联合验证,一个商品只能收藏一次
        validators = [
            UniqueTogetherValidator(
                queryset=UserFav.objects.all(),
                fields=('user', 'goods'),
                #message自定义错误消息
                message="已经收藏"
            )
        ]
        model = UserFav
        #收藏的时候需要返回商品的id,因为取消收藏的时候必须知道商品的id是多少
        fields = ("user", "goods",'id')

 

 2)user_operation/views.py

# user_operaton/views.py

from rest_framework import viewsets
from rest_framework import mixins
from .models import UserFav
from .serializers import UserFavSerializer

class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin):
    '''
    用户收藏
    '''
    queryset = UserFav.objects.all()
    serializer_class = UserFavSerializer

 

 3)urls.py配置:

# 配置用户收藏的url
router.register(r'userfavs', UserFavViewset, base_name="userfavs")

 上述操作是在未设置权限的情况下的,这种情况下用户可以对所有收藏数据进行任意操作,比如删除其他用户收藏信息,查看其他用户收藏信息,这样是很不安全的,因此需要做相关权限配置。

  1. 客户只能看到与自己相关的收藏信息
  2. 客户只能操作与自己相关的收藏信息

1)我们来自定义用户权限:

  utils文件夹下新建permissions.py:用于权限相关的操作

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    只读操作/只能操作当前用户相关数据
    """
    def has_object_permission(self, request, view, obj):
        #  GET、 HEAD or OPTIONS请求允许操作,因为都是安全的
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `owner`.
        #确定是当前用户才能进行其他操作
        return obj.user == request.user

 

 2)user_operation/views:

  • 注释掉 :queryset = UserFav.objects.all()  # 所有用户所有收藏信息
  • 重写get_queryset方法,将原queryset(所有收藏信息),改成当前用户的所有收藏信息
  • 加入权限认证
  • 取消JWT全局用户验证,在需要验证的的地方进行JWT验证。因为很多数据页面是运行未登录用户查看的,一般只有需要用户操作的地方才需要加JWT用户验证,注销setting.py下REST_FRAMEWORK:
    # 'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
  • 继承 mixins.RetrieveModelMixin :可以获取单条收藏的信息

 lookup_field 解释:

  搜索字段,url搜某条收藏记录时:http://127.0.0.1:8000/userfavs/id/ ,默认id是收藏信息的自增id,我们需要将其改成商品的id,这样我们要获取某个商品是否被收藏,就可以根据url中商品id直接查看情况了。

  lookup_field = 'goods_id'

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
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication

class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin):
    '''
    用户收藏
    '''
    serializer_class = UserFavSerializer
    #permission是用来做权限判断的
    permission_classes = (IsAuthenticated,IsOwnerOrReadOnly)
    #auth使用来做用户认证的
    authentication_classes = (JSONWebTokenAuthentication,SessionAuthentication)
    #搜索的字段
    lookup_field = 'goods_id'

    def get_queryset(self):
        #只能查看当前登录用户的收藏,不会获取所有用户的收藏
        return UserFav.objects.filter(user=self.request.user)

 注意:authentication_classes 中只做了JSONWebTokenAuthentication认证,是会被判为登录失败的,因为SessionAuthentication认证中无相关数据记录,因此在做用户认证时需要将两者都添加进来。

 

3)前端vue:

//收藏
export const addFav = params => { return axios.post(`${local_host}/userfavs/`, params) }

//取消收藏
export const delFav = goodsId => { return axios.delete(`${local_host}/userfavs/`+goodsId+'/') }

export const getAllFavs = () => { return axios.get(`${local_host}/userfavs/`) }

//判断是否收藏
export const getFav = goodsId => { return axios.get(`${local_host}/userfavs/`+goodsId+'/') }

 

2、动态设置serializer和permission获取用户信息

个人资料的修改:

 

 

在之前我们创建了UserViewset类,用于用户注册功能(CreateModelMixin),其实可以另创一个类用于用户资料修改等。但为了突出serializer、permission的动态效果,我们选择在UserViewset类中直接添加新的功能。
首先,修改用户资料,添加:继承mixins.RetrieveModelMixin,然后:
1)重载 get_object方法,method.update、delete时,会触发此方法:
# 获取当前用户,然后才能修改数据等
def get_object(self):
    return self.request.user

 

2)重载 get_permissions 方法:
 用户注册时,不需要认证处理;用户修改信息时,需要认证权限:已登录、当前用户
# 返回列表类型,权限相关会遍历该列表中的方法(对象/实例)
def get_permissions(self):
        if self.action == "retrieve": # 修改用户信息
            return [permissions.IsAuthenticated()]
        elif self.action == "create": # 新用户注册
            return []

        return []

重载 get_permissions 前,我们也需要将认证权限加进来,两者结合才是完整的权限认证:

from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication

authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication)

 

  3)接下来是重载get_serializer_class 方法,为什么重载get_serializer_class方法?

 因为,用户注册时,我们序列化了UserRegSerializer,界面中只需要提供手机号及验证码等,而修改信息时我们需要将用户相关信息都序列化提供给前端显示,此时UserRegSerializer就不能用了,我们需要再创建一个序列化,

这样的话就有两个序列化类存在了,我们在views中编写时不能两个序列化一起用,因此我们便需要重载get_serializer_class方法,类似get_permissions,当用户注册时,序列化UserRegSerializer类;当用户修改信息时,我们序

列化另外一个类。

 在serializers.py中新建:UserDetailSerializer

class UserDetailSerializer(serializers.ModelSerializer):
    """
    用户详情
    """
    class Meta:
        model = User
        fields = ("name", "gender", "birthday", "email","mobile")

  重载 get_serializer_class 方法:

def get_serializer_class(self):
        if self.action == "retrieve": # 修改用户信息
            return UserDetailSerializer
        elif self.action == "create": # 新用户注册
            return UserRegSerializer

        return UserDetailSerializer

注意: get_permissions方法、get_serializer_class方法中,都用到了self.action(request.method) ,这是在viewsets类中才有,才能调用的,如果是APIview是没有此方法的

 views.py中 UserViewset 完整代码:

class UserViewset(CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,viewsets.GenericViewSet):
    """
    create:
        用户注册
    retrieve:
        获取用户信息
    update:
        更新用户信息
    partial_update:
        更新用户信息(部分更新)
    """
    serializer_class = UserRegSerializer
    queryset = User.objects.all()
    authentication_classes = (JSONWebTokenAuthentication,SessionAuthentication) # 用户认证

    def get_permissions(self): # 权限
        if self.action == "retrieve":  # 获取用户信息
            return [permissions.IsAuthenticated()]
        elif self.action == "create":  # 新用户注册
            return []
        return []

    def get_serializer_class(self): # 用户信息序列化
        if self.action == "retrieve":  # 获取用户信息
            return UserDetailSerializer
        elif self.action == "create":  # 新用户注册
            return UserRegSerializer
        return UserDetailSerializer

    def create(self, request, *args, **kwargs):  # 重载create方法
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)
        re_dict = serializer.data
        payload = jwt_payload_handler(user)
        re_dict["token"] = jwt_encode_handler(payload)  # 设置token
        re_dict["name"] = user.name if user.name else user.username  # 设置用户名

        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    # 获取当前用户,
    def get_object(self):
        return self.request.user

    def perform_create(self, serializer):
        return serializer.save()
View Code

 

 访问url:127.0.0.1:8000/users/1/    #GET方法,第一个用户(admin):

 可以看到访问时数据已经展示出来了,前端只有连上接口配好前端页面,用户一访问该url,页面便能将相关数据展示出来了。

 

注意:因为重载get_object,获取到的用户即是当前用户,所以无论调试还是用户打开页面,无论url中设置id是多少,系统中找到的都是当前用户,展示的都是当前用户的信息。如果调试时需要获取任意用户的信息,注释掉get_object的重载方法就可以了


 

 上述介绍了获取用户信息,接下来就是用户修改信息之后,我们需要帮用户保存,修改信息并保存很容易,前面我们已经把需要的基本都完成了,现在只需要让 UserViewset 继承 mixins.UpdateModelMixin 就可以实现信息修改后的保存了:

class UserViewset(CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,viewsets.GenericViewSet):

 至此,(用户注册)、获取用户信息、修改用户信息并保存等功能便完成了

UserViewset 完整代码:

class UserViewset(CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,viewsets.GenericViewSet):
    """
    create:
        用户注册
    retrieve:
        获取用户信息
    update:
        更新用户信息
    partial_update:
        更新用户信息(部分更新)
    """
    serializer_class = UserRegSerializer
    queryset = User.objects.all()
    authentication_classes = (JSONWebTokenAuthentication,SessionAuthentication) # 用户认证

    def get_permissions(self): # 权限
        if self.action == "retrieve":  # 获取用户信息
            return [permissions.IsAuthenticated()]
        elif self.action == "create":  # 新用户注册
            return []
        return []

    def get_serializer_class(self): # 用户信息序列化
        if self.action == "retrieve":  # 获取用户信息
            return UserDetailSerializer
        elif self.action == "create":  # 新用户注册
            return UserRegSerializer
        return UserDetailSerializer

    def create(self, request, *args, **kwargs):  # 重载create方法
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)
        re_dict = serializer.data
        payload = jwt_payload_handler(user)
        re_dict["token"] = jwt_encode_handler(payload)  # 设置token
        re_dict["name"] = user.name if user.name else user.username  # 设置用户名

        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    # 获取当前用户,
    def get_object(self):
        return self.request.user

    def perform_create(self, serializer):
        return serializer.save()
View Code

 

页面效果:可以获取用户信息、修改信息 、保存信息

 


 

3.1、用户收藏功能 —— 续集 

 之前我们完成了用户的收藏功能,当用户点击收藏时系统会自动收藏该商品,用户删除时系统会自动删除该商品,通过url访问也能获取当前用户收藏的商品信息,

但之前的收藏操作中,我们序列化的UserFavSerializer ,只是给前端返回了商品id,而我们展示用户收藏的商品信息,需要用到goods外键关联的商品信息,如:

 

因此,我们需要另外序列化用户收藏,再通过重载 get_serializer_class方法,动态序列化我们想要的收藏信息。

 1)user_operation/serializer.py中添加:

class UserFavDetailSerializer(serializers.ModelSerializer):
    '''
    用户收藏详情
    要展示商品详情,则需结合商品序列化,重新创建user收藏类序列化
    '''
    goods = GoodsSerializer()
    class Meta:
        model = UserFav
        fields = ("goods", "id")  # goods是该商品的所有详细信息

 2)user_operation/views.py中,重载 get_serializer_class :

def get_serializer_class(self):
        if self.action == "list":
            return UserFavDetailSerializer
        elif self.action == "create":
            return UserFavSerializer
        return UserFavSerializer

 user_operation/views.py中,用户收藏功能完整代码:

from rest_framework import viewsets
from rest_framework import mixins
from .models import UserFav
from .serializers import UserFavSerializer,UserFavDetailSerializer
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication

class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin):
    '''
    list:
        获取用户收藏
    create:
        新增用户收藏
    destroy:
        删除用户收藏
    '''
    serializer_class = UserFavSerializer
    #permission是用来做权限判断的
    permission_classes = (IsAuthenticated,IsOwnerOrReadOnly)
    #auth使用来做用户认证的
    authentication_classes = (JSONWebTokenAuthentication,SessionAuthentication)
    #搜索的字段
    lookup_field = 'goods_id'

    def get_serializer_class(self):
        if self.action == "list":
            return UserFavDetailSerializer
        elif self.action == "create":
            return UserFavSerializer
        return UserFavSerializer

    def get_queryset(self):
        #重新get_queryset方法,获取当前用户相关所有收藏信息
        return UserFav.objects.filter(user=self.request.user)
UserFavViewset

 

3.2、用户留言功能

1)user_operation/serializers.py 新增LeavingMessageSerializer :留言相关数据序列化

class LeavingMessageSerializer(serializers.ModelSerializer):
    '''
    用户留言
    '''
    # 获取当前登录的用户, 隐藏不显示到api接口
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    #read_only:只返回,post时候可以不用提交,format:格式化输出
    add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')
    class Meta:
        model = UserLeavingMessage
        fields = ("user", "message_type", "subject", "message", "file", "id" ,"add_time")

2)user_operation/views.py 新增 LeavingMessageViewset:

class LeavingMessageViewset(mixins.ListModelMixin, mixins.DestroyModelMixin, mixins.CreateModelMixin,
                            viewsets.GenericViewSet):
    """
    list:
        获取用户留言
    create:
        添加留言
    delete:
        删除留言功能
    """

    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    serializer_class = LeavingMessageSerializer

    # 只能看到自己的留言
    def get_queryset(self):
        return UserLeavingMessage.objects.filter(user=self.request.user)

3)urls.py配置:

# 配置用户留言的url
router.register(r'messages', LeavingMessageViewset, base_name="messages"

可以进行操作:获取、添加、删除留言:

 


 

 3.3、用户收货地址

 实现方法与3.2 用户留言差不多

1)user_operation/serializers.py 新增AddressSerializer:收货地址信息序列化

class AddressSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')

    class Meta:
        model = UserAddress
        fields = ("id", "user", "province", "city", "district", "address", "signer_name", "add_time", "signer_mobile")

 

2)user_operation/views.py 新增 LeavingMessageViewset:

class AddressViewset(viewsets.ModelViewSet):
    """
    收货地址管理
    list:
        获取收货地址
    create:
        添加收货地址
    update:
        更新收货地址
    delete:
        删除收货地址
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    serializer_class = AddressSerializer

    def get_queryset(self):
        return UserAddress.objects.filter(user=self.request.user)

 

3)urls.py配置:

# 配置收货地址
router.register(r'address',AddressViewset , base_name="address")

 

posted on 2018-09-13 22:40  Eric_nan  阅读(485)  评论(0编辑  收藏  举报