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


 一、购物车功能

 1、实现购物车获取购物车商品列表信息、添加购物车商品数量、删除购物车商品

1)trade/serializer.py:序列化购物车数据

 几点说明:

  1. serializers.Serializer中没有get(list)、post(create)方法,需要自定义。
  2. views.py中获取当前用户 代码操作:self.request.user  ; serializers.py中,要获取当前用户,代码:self.context["request"].user ,存放于context当中。
  3. goods是一个外键,之前我们序列化goods商品时,goods/serializers.py中有用到序列化的CategorySerializer来展示外键相关信息,一般用list方法访问时使用这种方式展示所需要的详细信息,不需要展示商品详情时不这么做。在购物车model中,因为使用了联合唯一(goods、nums),不允许我们同一个goods+nums添加多个,否则会报错,所以我们不用耦合性较高的ModelSerializers,而是用Serializers。外键处理则使用DRF提供的PrimaryKeyRelatedField字段处理:
    goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())
    在serializers.Serializer中,‘queryset=Goods.objects.all()’这句是必须要写的,获取所有的商品数据,是个querysets集合,
    在serializers.ModelSerializer中,该语句是这样:goods = serializers.PrimaryKeyRelatedField(required=True, many=True,read_only),
    两句代码效果是一样的,第二句是因为内部有model,会自己映射,所以不用添加queryset搜查所有数据。
  4. goods = GoodsSerializer():使用序列化这种方式,会将提交的某goods商品所有信息以序列化形式都展示出来,需要全部填写才能提交
    goods = serializers.PrimaryKeyRelatedField:是个querysets集合,只会显示model中(__str__)return的字段信息,比如商品的名称(name),不需要我们操作。
    购物车需要获取的只是goods中的商品名称,故用第二种,不能用第一种序列化的方式。
  5. serializers.Serializer中,create()、update()两个方法,当需要用到时,需要我们在serializers中重载,否则会报错:`create()` must be implemented 。
    而serializers.ModelSerializer中,系统已经简单帮我们实现了这两个方法,不需要我们重载
from .models import ShoppingCart
from rest_framework import serializers
from goods.models import Goods

class ShopCartSerializer(serializers.Serializer):
    #获取当前登录的用户
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    nums = serializers.IntegerField(required=True, label="数量",min_value=1,
                                    error_messages={
                                        "min_value":"商品数量不能小于一",
                                        "required": "请选择购买数量"
                                    })
    #这里是继承Serializer,必须指定queryset对象,如果继承ModelSerializer则不需要指定
    #goods是一个外键,可以通过这方法获取goods object中所有的值
    goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())

    #继承的Serializer没有save功能,必须写一个create方法
    def create(self, validated_data):
        # validated_data是已经处理过的数据
        #获取当前用户
        # view中:self.request.user;serizlizer中:self.context["request"].user
        user = self.context["request"].user
        nums = validated_data["nums"]
        goods = validated_data["goods"]

        existed = ShoppingCart.objects.filter(user=user, goods=goods)
        #如果购物车中有记录,数量+nums
        #如果购物车车没有记录,就创建
        if existed:
            existed = existed[0]
            existed.nums += nums
            existed.save()
        else:
            #添加到购物车
            existed = ShoppingCart.objects.create(**validated_data)

        return existed

 2)trade/views.py:

 重载 get_queryset 方法,只查找与当前客户相关的购物车数据

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from .serializers import ShopCartSerializer
from .models import ShoppingCart

class ShoppingCartViewset(viewsets.ModelViewSet):
    """
    购物车功能
    list:
        获取购物车详情
    create:
        加入购物车
    delete:
        删除购物记录
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

    serializer_class = ShopCartSerializer

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

 

3)urls.py配置:

# 购物车
router.register(r'shopcarts', ShoppingCartViewset, base_name="shopcarts")

 

  

 


 

 上述已经完成了当前用户购物车数据获取、购物车商品创建,接下来我们来实现购物车商品数据更新:更新商品数量

  更新数据,需要用到update () 方法,因此,我们需要在serializers中重载该方法:

1)trade/serializer.py下的 ShopCartSerializer 添加:

def update(self, instance, validated_data):
        # 修改商品数量
        instance.nums = validated_data["nums"]
        instance.save()
        return instance

 2)在view中要把商品id传过去:

 因为更新单条数据,或者删除单条数据,需要用到商品id。

 lookup_field = "goods_id"

trade/views.py 完整代码:

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from .serializers import ShopCartSerializer
from .models import ShoppingCart

class ShoppingCartViewset(viewsets.ModelViewSet):
    """
    购物车功能
    list:
        获取购物车详情
    create:
        加入购物车
    delete:
        删除购物记录
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

    serializer_class = ShopCartSerializer
    lookup_field = "goods_id"
    
    def get_queryset(self):
        return ShoppingCart.objects.filter(user=self.request.user)
ShoppingCartViewset

此时,我们访问购物车链接时,页面效果是这样的:

 

原因是因为我们序列化只返回了数量,跟一个goods querysets集合,字段缺失无法正常显示。此时我们就需要用到serializers动态方法,实现list访问时展示购物车商品信息:

1)trade/serializer.py:创建 ShopCartDetailSerializer ,购物车商品详情

class ShopCartDetailSerializer(serializers.ModelSerializer):
    '''
    购物车商品详情信息
    '''
    # 一个购物车对应一个商品
    goods = GoodsSerializer(many=False, read_only=True)
    class Meta:
        model = ShoppingCart
        fields = ("goods", "nums")

 

2)views中,注释掉:serializer_class = ShopCartSerializer ,重载:get_serializer_class() 方法

def get_serializer_class(self):
        if self.action == 'list':
            return ShopCartDetailSerializer
        else:
            return ShopCartSerializer

此时再访问购物车页面,效果就出来了:

 

这样,购物车相关功能就完成了。

购物车serializers.py完整代码:

from rest_framework import serializers

from .models import ShoppingCart
from goods.models import Goods
from goods.serializers import GoodsSerializer


class ShopCartDetailSerializer(serializers.ModelSerializer):
    '''
    购物车商品详情信息
    '''
    # 一个购物车对应一个商品
    goods = GoodsSerializer(many=False, read_only=True)
    class Meta:
        model = ShoppingCart
        fields = ("goods", "nums")


class ShopCartSerializer(serializers.Serializer):
    #获取当前登录的用户
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    nums = serializers.IntegerField(required=True, label="数量",min_value=1,
                                    error_messages={
                                        "min_value":"商品数量不能小于1",
                                        "required": "请选择购买数量"
                                    })
    #goods是一个外键,可以通过这方法获取goods object中所有的值
    goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())
    print("ser--goods:",goods)

    #继承的Serializer没有save功能,必须写一个create方法
    def create(self, validated_data):
        # validated_data是已经处理过的数据
        # 获取当前用户 → view中:self.request.user;serizlizer中:self.context["request"].user
        user = self.context["request"].user
        nums = validated_data["nums"]
        goods = validated_data["goods"]

        existed = ShoppingCart.objects.filter(user=user, goods=goods)
        #如果购物车中有记录,数量+nums;如果没记录就创建,数量为nums
        if existed:
            existed = existed[0]
            existed.nums += nums
            existed.save()
        else:
            #添加到购物车
            existed = ShoppingCart.objects.create(**validated_data)

        return existed

    def update(self, instance, validated_data):
        # 修改商品数量
        instance.nums = validated_data["nums"]
        instance.save()
        return instance
View Code

 

 购物车views.py完整代码:

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from .serializers import ShopCartSerializer,ShopCartDetailSerializer
from .models import ShoppingCart

class ShoppingCartViewset(viewsets.ModelViewSet):
    """
    购物车功能
    list:
        获取购物车详情
    create:
        加入购物车
    delete:
        删除购物记录
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

    def get_serializer_class(self):
        if self.action == 'list':
            return ShopCartDetailSerializer
        else:
            return ShopCartSerializer

    lookup_field = "goods_id"

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

 

 注意:关于重载 get_object方法、get_queryset方法,两者的差别

 get_object():获取当前用户 ,在url访问方式:获取某个商品详情(get)、更新某个商品信息(update)、删除某个商品信息(delete)时,会调用

 get_queryset():url的访问方式中均会调用

如果获取所有数据(list方法),同时又有get、update、delete方法:

 1、需要获取到的是所有用户的所有数据,则使用get_object方法

 2、需要获取到的是当前用户的所有数据,则使用get_queryset方法,不需要get_object方法

def get_object(self):
    return self.request.user


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

 二、订单管理接口

 客户到购物车,进行结算 → 创建订单 →保存订单信息、保存订单内每个商品的详情信息 → 查看当前用户所有订单、创建订单、删除订单,用:OrderSerializer ;查看某订单详情用:OrderDetailSerializer

views.py:

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from rest_framework import mixins
from .serializers import ShopCartSerializer,ShopCartDetailSerializer,OrderDetailSerializer,OrderSerializer
from .models import ShoppingCart,OrderGoods,OrderInfo

class OrderViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin,
                   viewsets.GenericViewSet):
    """
    订单管理
    list:
        获取个人订单
    delete:
        删除订单
    create:
        新增订单
    retrieve:
        获取某订单详情
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

    # 动态配置serializer
    def get_serializer_class(self):
        if self.action == "retrieve":
            return OrderDetailSerializer
        return OrderSerializer

    # 获取订单列表
    def get_queryset(self):
        return OrderInfo.objects.filter(user=self.request.user)

    # 在订单提交保存之前还需要多两步步骤,所以这里自定义perform_create方法
    # 1.将购物车中的商品保存到OrderGoods中
    # 2.清空购物车
    def perform_create(self, serializer):
        order = serializer.save() # 保存订单信息
        # 获取购物车所有商品,存于订单内的商品详情中,然后清空购物车
        shop_carts = ShoppingCart.objects.filter(user=self.request.user)
        for shop_cart in shop_carts:
            order_goods = OrderGoods()
            order_goods.goods = shop_cart.goods
            order_goods.goods_num = shop_cart.nums
            order_goods.order = order
            order_goods.save()
            # 清空购物车
            shop_cart.delete()
        return order
OrderViewset

 

trade/serializers.py:

#订单中的商品
class OrderGoodsSerialzier(serializers.ModelSerializer):
    goods = GoodsSerializer(many=False)
    class Meta:
        model = OrderGoods
        fields = "__all__"

#订单商品信息
# goods字段需要嵌套一个OrderGoodsSerializer
class OrderDetailSerializer(serializers.ModelSerializer):
    goods = OrderGoodsSerialzier(many=True)
    class Meta:
        model = OrderInfo
        fields = "__all__"

class OrderSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    #生成订单的时候,这些只读,不能填写添加
    pay_status = serializers.CharField(read_only=True)
    trade_no = serializers.CharField(read_only=True)
    order_sn = serializers.CharField(read_only=True)
    pay_time = serializers.DateTimeField(read_only=True)
    nonce_str = serializers.CharField(read_only=True)
    pay_type = serializers.CharField(read_only=True)


    def generate_order_sn(self):
        #生成订单号
        # 当前时间+userid+随机数
        from random import Random
        random_ins = Random()
        order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),
                                                       userid=self.context["request"].user.id,
                                                       ranstr=random_ins.randint(10, 99))
        return order_sn

    def validate(self, attrs):
        #validate中添加order_sn,然后在view中就可以save
        attrs["order_sn"] = self.generate_order_sn()
        return attrs

    class Meta:
        model = OrderInfo
        fields = "__all__"
View Code

 

urls.py配置:

# 订单的url
router.register(r'orders', OrderViewset, base_name="orders")

 

 

 


 

 三、pycharm远程代码调试

 参考:https://www.cnblogs.com/Eric15/articles/9593662.html

 Ubuntu系统下操作:

 1)新建虚拟环境

mkvirtualenv --python=/usr/bin/python3 mxshop

2)导出win系统下MxOnline开发环境中所依赖的包:

  导出指令:pip freeze > requirements.txt

  到当前目录下找到:requirements.txt ,将此文件复制到linux下的MxOnline虚拟环境中

  读取文件 并安装到虚拟环境中:pip install -r requirements.txt

 3)将win下mxshop数据库数据,传输到Ubuntu中的mysql中:

 win下用Navicat连接Ubuntu数据库,然后新建数据库:

 

 接着,将数据传输过去:

 


 

4)使用pycharm连接服务器ip,并将项目同步到Ubuntu中

做以下操作前,请先确定:

  1. 自己有个服务站点:比如阿里云服务端
  2. 已经在服务端创建好规则,开放好相应端口:

 

 

 

上面条件具备后,可以开始我们的操作(Ubuntu环境下):

 首先,在当前用户下新建目录:mkdir mxshop

 然后利用pycharm来同步项目:

  切记,setting中配置:ALLOWED_HOSTS = ['*']

 步骤:Tools-->>Deployment-->>Configuration  ,新增配置

 

 

 

 

 设置好后,在connection下 → 点击“Test SFTP connection”,测试连接,如果成功,则表示连上服务器,失败则需要找原因

接着,如下操作:
Tools-->>Deployment-->>Configuration-->>Upload to MxShop ,
会将本地当前项目同步到Ubuntu中的mxshop项目中取

5)接下来就可以进行我们的pycharm远程调试了
点击设置:

找到pycharm下的project interpreter:
 将其设置为服务器虚拟环境的python ,这样相当于在服务器上运行项目了,如下操作:

  

然后就会把服务器虚拟环境中的文件全部拷贝到本地

点“ok”后,还会加载一些东西,耐心等待一会,完成后

 设置Host 0.0.0.0   端口  8000

 

 

pycharm上运行项目,相当于在服务器上运行项目了,访问url:



 
posted on 2018-09-14 02:05  Eric_nan  阅读(753)  评论(0编辑  收藏  举报