订单建模,包含订单基本信息
和订单商品
两张表
### 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)
功能 --- 提交订单展示页
-
请求方式
请求方法 请求地址 POST http://127.0.0.1:8000/orders/ -
请求参数
请求头 key 值 类型 是否必传 说明 headers Authorization 'JWT ' + token string 是 JWT字符串一定要加空格(后端以空格进行拆分) 请求参数 address 收货地址 请求参数 pay_method 支付方式 -
响应成功结果:
OrderInfo
对象(前端可以提取 order_id,total_amount 渲染页面) -
当用户点击```提交订单按钮``时,前端只传两个字段
- 收货地址
- 支付方式(货到付款/支付宝)
- 商品的数据,不要从这里取(虽然用户该页面无法修改,但可以再打开购物车页面,进行编辑)
...... on_order_submit: function(){ if (this.order_submitting == false){ this.order_submitting = true; axios.post(this.host+'/orders/', { // 提交这两个字段 address: this.nowsite, pay_method: this.pay_method }, { headers: { 'Authorization': 'JWT ' + this.token }, responseType: 'json' }) .then(response => { location.href = '/order_success.html?order_id='+response.data.order_id +'&amount='+this.payment_amount +'&pay='+this.pay_method; }) .catch(error => { this.order_submitting = false; alert(error.response.data[0]); }) } }
-
当用户提交订单以后,我们把订单信息保存下来,以便后续用户根据订单信息支付商品费用
### serializers ...... # 订单信息序列化器 class CommitOrderSerializer(serializers.ModelSerializer): class Meta: model = OrderInfo extra_kwargs = { 'order_id': {'read_only': True}, 'address': {'write_only': True}, # 这两个字段均需校验 'pay_method': {'write_only', True}, } def create(self, validated_data): ...... ### views ...... class CommitOrderView(CreateAPIView): authentication_classes = [JSONWebTokenAuthentication, ] permission_classes = [IsAuthenticated, ]
- create - 获取 user - order_id: timezone.localtime().strftime('%Y%m%d%H%M%S') + '0'*9 + str(user.id) - address,pay_method # 如果是支付宝,就显示未支付;其他显示 未发货 - status: (OrderInfo.ORDER_STATUS_ENUM['UNPAID'] # 1 if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] # 2 else OrderInfo.ORDER_STATUS_ENUM['UNSEND']) # 2 - total_count,total_amount: 0; freight = 10 OrderInfo.create(.....)
-
首先保存订单信息,即生成一条
OrderInfo模型记录
### serializers ...... class CommitOrderSerializer(serializers.ModelSerializer): class Meta: ...... def create(self, validated_data): user = self.context['request'].user # 手动生成 order_id order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + '0' * 9 + str(user.id) address = validated_data.get('address') pay_method = validated_data.get('pay_method') # 如果是支付宝,就显示-未支付;其他显示-未发货 status = (OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND']) total_count = 0 # 先用假数据演练 total_amount = 0 freight = 10 OrderInfo.objects.create( order_id=order_id, user=user, address=address, total_count=total_count, total_amount=total_amount, freight=freight, pay_method=pay_method, status=status )
- 从redis获取被勾选的商品信息,更新库存和销量
class CommitOrderSerializer(serializers.ModelSerializer):
class Meta:
......
def create(self, validated_data):
......
OrderInfo.objects.create(
......
)
# 修改商品库存,销量
conn = get_redis_connection('cart')
cart_dict = conn.hgetall('cart_{}'.format(user.id))
selected_ids = conn.smembers('selected_{}'.format(user.id))
for sku_id in selected_ids:
sku_obj = SKU.objects.get(id=int(sku_id))
count = int(cart_dict[sku_id])
if count > sku_obj.stock:
raise serializers.ValidationError('库存不足')
sku_obj.stock -= count
sku_obj.sales += count
sku_obj.save()
- 接下来要做的事情
- 保存订单商品信息
- 累加商品总数量和总价(之前默认值均为0)
- 加入邮费并保存订单信息,最后返回订单信息模型
class CommitOrderSerializer(serializers.ModelSerializer):
class Meta:
......
def create(self, validated_data):
......
order_info_obj = OrderInfo.objects.create( # 接收订单对象,以便后续操作
......
)
# 修改商品库存,销量
conn = get_redis_connection('cart')
......
for sku_id in selected_ids:
sku_obj = SKU.objects.get(id=int(sku_id))
......
sku_obj.save()
OrderGoods.objects.create(
order=order_info_obj,
sku=sku_obj,
count=count,
price=sku_obj.price
)
order_info_obj.total_count += count
order_info_obj.total_amount += (sku_obj.price)*count
order_info_obj.total_amount += order_info_obj.freight
order_info_obj.save()
return order_info_obj
- 上述代码存在的问题
- 触发异常时: raise serializers.ValidationError('库存不足')
- 此时 order_info_obj 记录已经生成,而这笔订单实际是失败的,不能生成订单让用户支付
- 在上述view中,我们同时操作了4张表,应该共同进退,要么一起成功,要么一起失败
- MySQL支持事务,刚好满足需求
- MySQL 默认并支持开启事务,每次操作一次表会默认拷贝一个副本,在副本上操作数据
若副本上成功操作数据,则让副本的数据覆盖源数据;若失败,就退回源数据
- 如果把上述同时操作的4张表看成一次事务,就可以满足需求,即4张表共同进退~
django事务API
- 参考网址
http://47.101.37.192/%E8%AF%BE%E4%BB%B6/%E7%BE%8E%E5%A4%9A%E5%95%86%E5%9F%8E%E8%AF%BE%E4%BB%B6/orders/commit/transaction.html
- 在
Django
中可以通过django.db.transaction
模块提供的atomic
来定义一个事务,atomic
提供两种方案实现事务
- 装饰器用法
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# 这些代码会在一个事务中执行
......
- with语句用法
from django.db import transaction
def viewfunc(request):
# 这部分代码不在事务中,会被 Django 自动提交
......
with transaction.atomic():
# 这部分代码会在事务中执行
......
- 两种方法取舍
- 装饰器用法:整个视图中所有 MySQL 数据库的操作都看做一个事务,范围太大,不够灵活
而且无法直接作用于类视图
- with 语句用法(推荐):可以灵活的有选择性的把某些 MySQL 数据库的操作看做一个事务
而且不用关心视图的类型
事务
中的保存点
在 Django 中,还提供了保存点的支持,可以在事务中创建保存点来记录数据的特定状态
数据库出现错误时,可以回滚到数据保存点的状态
from django.db import transaction
# 创建保存点
save_id = transaction.savepoint()
# 回滚到保存点
transaction.savepoint_rollback(save_id)
# 提交从保存点到当前状态的所有数据库事务操作
transaction.savepoint_commit(save_id)
- 把
事务
运用到项目,实现共同进退
class CommitOrderSerializer(serializers.ModelSerializer):
class Meta:
model = OrderInfo
extra_kwargs = {
'order_id': {'read_only': True},
'address': {'write_only': True},
'pay_method': {'write_only', True},
}
def create(self, validated_data):
......
freight = 10
with transaction.atomic():
save_point = transaction.savepoint() # 创建还原点
try:
order_info_obj = OrderInfo.objects.create(
order_id=order_id,
user=user,
address=address,
total_count=total_count,
total_amount=total_amount,
freight=freight,
pay_method=pay_method,
status=status
)
conn = get_redis_connection('cart')
cart_dict = conn.hgetall('cart_{}'.format(user.id))
selected_ids = conn.smembers('selected_{}'.format(user.id))
for sku_id in selected_ids:
sku_obj = SKU.objects.get(id=int(sku_id))
count = int(cart_dict[sku_id])
if count > sku_obj.stock:
raise serializers.ValidationError('库存不足')
sku_obj.stock -= count
sku_obj.sales += count
sku_obj.save()
OrderGoods.objects.create(
order=order_info_obj,
sku=sku_obj,
count=count,
price=sku_obj.price
)
order_info_obj.total_count += count
order_info_obj.total_amount += (sku_obj.price)*count
order_info_obj.total_amount += order_info_obj.freight
order_info_obj.save()
except Exception:
transaction.savepoint_rollback(save_point) # 异常就回滚到还原点,触发库存异常
raise serializers.ValidationError('库存不足')
else:
transaction.savepoint_commit(save_point) # 没有异常就提交事务
return order_info_obj
用户同时下单引发的库存问题
-
若
A用户
和B用户
同时下单,可能造成库存不足而多个用户却下单成功的场景- 比如同时查询了库存,此时库存充足,而A用户网速好,优先修改了库存量;
由于B用户是同时查询,所以也会查询成功,然后和A用户一样的操作
最终结果:库存15个,却卖出18个...商家自己填坑!
- 比如同时查询了库存,此时库存充足,而A用户网速好,优先修改了库存量;
-
解决办法:有三种方式,悲观锁,乐观锁,任务队列
- 悲观锁: 当查询某条记录时,即让数据库为该记录加锁,锁住记录后其他人无法操作,使用类似如下语法
select stock from tb_sku where id=1 for update;
SKU.objects.select_for_update().get(id=1)
- 缺点: 类似于我们在多线程资源竞争时添加的互斥锁,容易出现死锁现象(即忘记释放锁)
而且用户只能等,用户体验并不好
- 乐观锁(推荐): 乐观锁并不是真实存在的锁,而是在更新的时候判断此时的库存是否是之前查询出的库存
如果相同,表示没人修改,可以更新库存,否则表示别人抢过资源,不再执行库存更新
update tb_sku set stock=2 where id=1 and stock=7
SKU.objects.filter(id=1, stock=7).update(stock=2)
- 任务队列: 将下单的逻辑放到任务队列中(如celery),将并行转为串行,所有人排队下单
比如开启只有一个进程的Celery,一个订单一个订单的处理
- 项目应用
class CommitOrderSerializer(serializers.ModelSerializer):
class Meta:
......
def create(self, validated_data):
......
with transaction.atomic():
......
for sku_id in selected_ids:
while True: # 让用户拥有无线下单的机会
sku_obj = SKU.objects.get(id=int(sku_id))
count = int(cart_dict[sku_id])
origin_stock = sku_obj.stock
if count > sku_obj.stock:
raise serializers.ValidationError('库存不足')
# sku_obj.stock -= count
# sku_obj.sales += count
# sku_obj.save()
# 先查询是否为原始数据,查询成功则更新库存和销量
# 查询不成功,就继续上面的下单流程(若还有库存,用户可以继续下单)
update_nums = SKU.objects.filter(stock=origin_stock,id=int(sku_id)).update(stock=origin_stock-count,sales=sku_obj.sales + count)
if update_nums == 0:
continue
OrderGoods.objects.create(
......
)
......
order_info_obj.total_amount += (sku_obj.price)*count
break # 成功下单就退出循环
order_info_obj.total_amount += order_info_obj.freight
order_info_obj.save()
except Exception:
transaction.savepoint_rollback(save_point)
raise serializers.ValidationError('库存不足')
else:
transaction.savepoint_commit(save_point)
return order_info_obj
MySQL事务隔离级别
-
定义: 指的是在处理同一个数据的多个事务中,一个事务修改数据后
其他事务何时能看到修改后的结果 -
MySQL数据库事务隔离级别主要有四种
- Serializable:串行化,一个事务一个事务的执行
- Repeatable read(默认设置):可重复读,无论其他事务是否修改并提交了数据,
在这个事务中看到的数据值始终不受其他事务影响
- Read committed:读取已提交,其他事务提交了对数据的修改后,本事务就能读取到修改后的数据值
- Read uncommitted:读取未提交,其他事务只要修改了数据,即使未提交,本事务也能看到修改后的数据值
- 使用乐观锁的时候,如果一个事务修改了库存并提交了事务,那其他的事务应该可以读取到修改后的数据值
所以不能使用可重复读的隔离级别,应该修改为读取已提交(Read committed)
- windows系统下,修改"my.ini",文件末尾增加这句
transaction-isolation=READ-COMMITTED
- 最后,清空购物车已结算商品
......
pl = conn.pipeline()
pl.hdel('cart_{}'.format(user.id),*cart_dict.keys())
pl.srem('selected_{}'.format(user.id),*selected_ids)
pl.execute()
return order_info_obj
- 完整代码如下
from apps.goods.models import SKU
from .models import OrderInfo, OrderGoods
from django.utils import timezone
from django.db import transaction
from django_redis import get_redis_connection
from rest_framework import serializers
class CommitOrderSerializer(serializers.ModelSerializer):
class Meta:
model = OrderInfo
fields = ['order_id', 'address', 'pay_method']
extra_kwargs = {
'order_id': {
'read_only': True,
},
'address': {
'write_only': True,
},
'pay_method': {
'write_only': True,
},
}
def create(self, validated_data):
user = self.context['request'].user
order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + '0' * 9 + str(user.id)
address = validated_data.get('address')
pay_method = validated_data.get('pay_method')
status = (OrderInfo.ORDER_STATUS_ENUM['UNPAID']
if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']
else OrderInfo.ORDER_STATUS_ENUM['UNSEND'])
total_count = 0
total_amount = 0
freight = 10
with transaction.atomic():
save_point = transaction.savepoint()
try:
order_info_obj = OrderInfo.objects.create(
order_id=order_id,
user=user,
address=address,
total_count=total_count,
total_amount=total_amount,
freight=freight,
pay_method=pay_method,
status=status
)
# 修改商品库存,销量
conn = get_redis_connection('cart')
cart_dict = conn.hgetall('cart_{}'.format(user.id))
selected_ids = conn.smembers('selected_{}'.format(user.id))
for sku_id in selected_ids:
while True:
sku_obj = SKU.objects.get(id=int(sku_id))
count = int(cart_dict[sku_id])
origin_stock = sku_obj.stock
if count > sku_obj.stock:
raise serializers.ValidationError('{}库存不足'.format(sku_obj.name))
update_nums = SKU.objects.filter(stock=origin_stock,id=int(sku_id)).update(stock=origin_stock-count,sales=sku_obj.sales + count)
if update_nums == 0:
continue
OrderGoods.objects.create(
order=order_info_obj,
sku=sku_obj,
count=count,
price=sku_obj.price
)
order_info_obj.total_count += count
order_info_obj.total_amount += (sku_obj.price)*count
break
order_info_obj.total_amount += order_info_obj.freight
order_info_obj.save()
except Exception:
transaction.savepoint_rollback(save_point)
raise serializers.ValidationError('{}库存不足'.format(sku_obj.name))
else:
transaction.savepoint_commit(save_point)
pl = conn.pipeline()
pl.hdel('cart_{}'.format(user.id),*cart_dict.keys())
pl.srem('selected_{}'.format(user.id),*selected_ids)
pl.execute()
return order_info_obj
展示订单信息
- 从
db
获取字段
,构造如下数据格式
- 前端传分页字段(query): page,page_size
- 订单号
- 订单创建时间
- sku商品名称,数量,单价,总价,图片
- 付款方式
- 分页
[
{
order_id:xxx,
create_time:xxx,
total_amount:xxx
pay_method:xxx,
skus:[
{
sku:{id:xxx,name:xxx,default_image_url:xxx},
count:xxx,
price:xxx
},
{......}
],
},
{......},
{......}
]
- 针对上面的数据格式,我们自定义两个
序列化器
来搞定它
### orders.serializers
......
### 订单商品序列化器(包含sku商品的相关信息)
class ShowOrderGoodsSerializer(serializers.ModelSerializer):
sku = serializers.SerializerMethodField()
class Meta:
model = OrderGoods
fields = ['sku', 'count','price']
read_only_fields = ['sku', 'count','price']
def get_sku(self,obj):
sku_dict = {}
sku_dict['id'] = obj.sku.id
sku_dict['name'] = obj.sku.name
sku_dict['default_image_url'] = obj.sku.default_image_url
return sku_dict
### 订单信息序列化器
class ShowOrderSerializer(serializers.ModelSerializer):
skus = ShowOrderGoodsSerializer(many=True)
class Meta:
model = OrderInfo
fields = ['order_id', 'pay_method','total_amount','create_time','skus']
read_only_fields = ['order_id', 'pay_method','total_amount','create_time','skus']
views
的逻辑如下
### orders.views
......
class ShowOrderView(APIView):
# 必要的用户校验
authentication_classes = [JSONWebTokenAuthentication, ]
permission_classes = [IsAuthenticated, ]
def get(self,request):
user = request.user
queryset = OrderInfo.objects.filter(user=user).all()
serializer = ShowOrderSerializer(queryset,many=True)
return Response(serializer.data)
### orders.urls
from django.conf.urls import url
from . import views
urlpatterns = [
......
url(r"^orders/user/$",views.ShowOrderView.as_view()),
]
- 测试数据,返回结果如下
[
{
"order_id": "2023042616361000000000012",
"pay_method": 1,
"total_amount": "30274.06",
"create_time": "2023-04-26T16:36:10.050187+08:00",
"skus": [
{
"sku": {
"id": 16,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 曜石黑 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdPeAXNDMAAYJrpessGQ9777651"
},
"count": 1,
"price": "4099.99"
},
{
"sku": {
"id": 13,
"name": "华为 HUAWEI P10 Plus 6GB+64GB 玫瑰金 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdLGARgBAAAVslh9vkK00474545"
},
"count": 1,
"price": "3388.01"
},
{
"sku": {
"id": 1,
"name": "Apple MacBook Pro 13.3英寸笔记本 银色",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrPB4GAWkTlAAGuN6wB9fU4220429"
},
"count": 2,
"price": "11388.03"
}
]
},
{
"order_id": "2023042616391500000000012",
"pay_method": 1,
"total_amount": "30274.06",
"create_time": "2023-04-26T16:39:15.107734+08:00",
"skus": [
{
"sku": {
"id": 16,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 曜石黑 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdPeAXNDMAAYJrpessGQ9777651"
},
"count": 1,
"price": "4099.99"
},
{
"sku": {
"id": 1,
"name": "Apple MacBook Pro 13.3英寸笔记本 银色",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrPB4GAWkTlAAGuN6wB9fU4220429"
},
"count": 2,
"price": "11388.03"
},
{
"sku": {
"id": 13,
"name": "华为 HUAWEI P10 Plus 6GB+64GB 玫瑰金 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdLGARgBAAAVslh9vkK00474545"
},
"count": 1,
"price": "3388.01"
}
]
},
{
"order_id": "2023042616484000000000012",
"pay_method": 1,
"total_amount": "7498.00",
"create_time": "2023-04-26T16:48:40.313562+08:00",
"skus": [
{
"sku": {
"id": 13,
"name": "华为 HUAWEI P10 Plus 6GB+64GB 玫瑰金 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdLGARgBAAAVslh9vkK00474545"
},
"count": 1,
"price": "3388.01"
},
{
"sku": {
"id": 16,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 曜石黑 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdPeAXNDMAAYJrpessGQ9777651"
},
"count": 1,
"price": "4099.99"
}
]
},
{
"order_id": "2023042715455700000000012",
"pay_method": 1,
"total_amount": "7898.00",
"create_time": "2023-04-27T15:45:57.547184+08:00",
"skus": [
{
"sku": {
"id": 16,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 曜石黑 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdPeAXNDMAAYJrpessGQ9777651"
},
"count": 1,
"price": "4099.99"
},
{
"sku": {
"id": 14,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 玫瑰金 移动联通电信4G手机 双卡双待",
"default_image_url": "http://192.168.11.39:8888/group1/M00/00/02/CtM3BVrRdMSAaDUtAAVslh9vkK04466364"
},
"count": 1,
"price": "3788.01"
}
]
}
]
- 如果把上述逻辑封装成
ListAPIView
,可以这么搞(代码没省多少)
### views
......
class ShowListOrderView(ListAPIView):
authentication_classes = [JSONWebTokenAuthentication, ]
permission_classes = [IsAuthenticated, ]
serializer_class = ShowOrderSerializer
def get_queryset(self):
return OrderInfo.objects.filter(user=self.request.user).all()
### urls
......
urlpatterns = [
......
# url(r"^orders/user/$",views.ShowOrderView.as_view()),
url(r"^orders/user/$",views.ShowListOrderView.as_view()),
]