订单建模,包含订单基本信息
和订单商品
两张表
### orders.models
from django.db import models
from utils.models import BaseModel
from users.models import UserInfo,Address
from goods.models import SKU
class OrderInfo(BaseModel):
'''
- 订单基本信息
- 用到 User 和 Address两个外键
'''
PAY_METHODS_ENUM = {
"CASH": 1,
"ALIPAY": 2
}
PAY_METHOD_CHOICES = (
(1, "货到付款"),
(2, "支付宝"),
)
ORDER_STATUS_ENUM = {
"UNPAID": 1,
"UNSEND": 2,
"UNRECEIVED": 3,
"UNCOMMENT": 4,
"FINISHED": 5
}
ORDER_STATUS_CHOICES = (
(1, "待支付"),
(2, "待发货"),
(3, "待收货"),
(4, "待评价"),
(5, "已完成"),
(6, "已取消"),
)
# 不使用默认自动生成的ID字段,而是自定义
order_id = models.CharField(max_length=64, primary_key=True, verbose_name="订单号")
user = models.ForeignKey(UserInfo, on_delete=models.PROTECT, verbose_name="下单用户")
address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="收货地址")
# 正整数
total_count = models.PositiveIntegerField(default=1, verbose_name="商品总数")
# 设置了精度的十进制数字(推荐使用)
total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")
freight = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="运费")
pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式")
status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")
class Meta:
db_table = "tb_order_info"
verbose_name = '订单基本信息'
verbose_name_plural = verbose_name
def __str__(self):
return self.order_id
class OrderGoods(BaseModel):
"""
- 订单商品
-两个外键: order & sku
"""
SCORE_CHOICES = (
(0, '0分'),
(1, '20分'),
(2, '40分'),
(3, '60分'),
(4, '80分'),
(5, '100分'),
)
order = models.ForeignKey(OrderInfo, related_name='skus', on_delete=models.CASCADE, verbose_name="订单")
sku = models.ForeignKey(SKU, on_delete=models.PROTECT, verbose_name="订单商品")
count = models.PositiveIntegerField(default=1, verbose_name="数量")
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="单价")
comment = models.TextField(default="", verbose_name="评价信息")
score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')
is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')
is_commented = models.BooleanField(default=False, verbose_name='是否评价了')
class Meta:
db_table = "tb_order_goods"
verbose_name = '订单商品'
verbose_name_plural = verbose_name
def __str__(self):
return self.sku.name
功能 --- 提交订单展示页
-
请求方式
请求方法 请求地址 GET http://127.0.0.1:8000/orders/settlement/ -
请求参数
请求头 key 值 类型 是否必传 说明 headers Authorization 'JWT ' + token string 是 JWT字符串一定要加空格(后端以空格进行拆分) -
响应成功结果:JSON
{ "freight":"100.00", "skus":[ { "id":10, "name":'华为xxxx手机', "default_image_url":"https://www.dfsdfsf.xsdfsdss", "price":"3788.00", "count":1 }, { "id":11, "name":'苹果xxxx收集', "default_image_url":"https://www.xxxx.yyyyyy", "price":"6700.00", "count":2 }, ] }
-
后端接口注意事项
- 用户收货地址(已有)
- 支付方式('货到付款'/'支付宝')
- 商品信息数据(不再提供修改功能)
-
前端要获取两块信息,当网页开始加载的时候,立即向后端发起请求
- 获取用户的收货地址
- 获取购物车结算的商品信息
...... mounted: function(){ // 获取地址信息 axios.get(this.host + '/addresses/', { headers: { 'Authorization': 'JWT ' + this.token }, responseType: 'json' }) .then(response => { this.addresses = response.data.addresses; this.nowsite = response.data.default_address_id; }) ...... // 获取结算商品信息 axios.get(this.host+'/orders/settlement/', { headers: { 'Authorization': 'JWT ' + this.token }, responseType: 'json' }) .then(response => { this.skus = response.data.skus; this.freight = response.data.freight; this.total_count = 0; this.total_amount = 0; for(var i=0; i<this.skus.length; i++){ var amount = parseFloat(this.skus[i].price)*this.skus[i].count; this.skus[i].amount = amount.toFixed(2); this.total_count += this.skus[i].count; this.total_amount += amount; } this.payment_amount = parseFloat(this.freight) + this.total_amount; this.payment_amount = this.payment_amount.toFixed(2); this.total_amount = this.total_amount.toFixed(2); }) ......
-
构造类似下面的数据格式,用两个序列化器来搞定
{
"freight":"100.00", # 订单序列化器
"skus":[ # sku序列化器
{
......
},
{
......
},
]
}
### orders.serializers
from apps.goods.models import SKU
from rest_framework import serializers
class CartSKUSerializer(serializers.ModelSerializer):
'''订单中,商品数据的序列化(提供给下面的序列化类使用)'''
count = serializers.IntegerField(label='购买数量') # count值从redis取
class Meta:
model = SKU
fields = ['id','name','price','default_image_url','count']
class OrderSettlementSerializer(serializers.Serializer):
'''订单序列化器'''
# 多条数据,要加上many,skus对应一个查询集
skus = CartSKUSerializer(many=True)
# 简单赋值
freight = serializers.DecimalField(max_digits=10,decimal_places=2,label='运费')
视图
: 从redis
取出购物车数据,构造数据,然后序列化返回给前端
from decimal import Decimal
from django_redis import get_redis_connection
from rest_framework.views import APIView
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializers import OrderSettlementSerializer
from apps.goods.models import SKU
class OrderSettlementView(APIView):
authentication_classes = [JSONWebTokenAuthentication, ]
permission_classes = [IsAuthenticated, ]
def get(self,request):
user = request.user # 代码能进来,说明验证无误,不用再try
conn = get_redis_connection('cart')
# 获取 redis 购物车数据,构造dict
redis_cart_dict = conn.hgetall('cart_{}'.format(user.id))
selected_ids = conn.smembers('selected_{}'.format(user.id))
cart_dict = {} # 把sku_id和count丢里面,给后面的queryset使用
for sku_id in selected_ids:
cart_dict[int(sku_id)] = int(redis_cart_dict[sku_id]) # 获取count
skus_queryset = SKU.objects.filter(id__in=cart_dict.keys())
for sku in skus_queryset:
sku.count = cart_dict[sku.id] # 把count加入queryset对象
freight = Decimal('10.00')
data_dict = { # 构造数据并序列化
'freight':freight,
'skus':skus_queryset
}
serializer = OrderSettlementSerializer(data_dict) # 单个对象,无需再加 many=True
return Response(serializer.data)