Django对接Amazon SP-API:数据持久化与模型设计咨询
Django + Amazon SP-API 仪表盘模型设计问题解答
背景说明
我正在用Amazon SP-API等外部API在Django里搭建简易仪表盘,目前会遍历100个带不同刷新令牌的账号拉取客户订单,推送到数据库,同时用定时任务(cronjob)调用Amazon API,通过Django的update_or_create实现数据的保存和更新。
当前使用的模型代码:
class VendorOrder(models.Model): id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID') purchase_order_number = models.CharField(max_length = 30) purchase_order_state = models.CharField(max_length = 30, default = "", null = True, blank = True) purchase_order_date = models.DateTimeField() last_updated_date = models.DateTimeField(null = True, blank = True) window_start = models.DateTimeField() window_end = models.DateTimeField() selling_party = models.CharField(max_length = 100) warehouse = models.CharField(max_length = 100) item_sequence_number = models.IntegerField(null = True, blank = True) buyer_product_identifier = models.CharField(max_length = 30, default ="", null = True, blank = True) vendor_product_identifier = models.CharField(max_length = 30, default ="", null = True, blank = True) ordered_quantity = models.DecimalField(max_digits=20, decimal_places=2, null = True, blank = True) accepted_quantity = models.DecimalField(max_digits=20, decimal_places=2, null = True, blank = True) received_quantity = models.DecimalField(max_digits=20, decimal_places=2, null = True, blank = True) net_cost = models.DecimalField(max_digits=20, decimal_places=2, null = True, blank = True) net_cost_currency = models.CharField(max_length = 10, default ="", null = True, blank = True) total_cost = models.DecimalField(max_digits=20, decimal_places=2, null = True, blank = True)
问题解答
1. 是否需要新建日期模型存储window_start和window_end?
不需要单独新建日期模型,理由如下:
window_start和window_end是采购订单级别的属性,每个purchase_order_number对应唯一的窗口日期,与订单本身强关联,拆分到单独模型会增加数据冗余和关联查询成本。- 可以先拉取订单基础数据存入数据库(将
window_start和window_end设为null=True),再调用第二个接口获取窗口日期,通过purchase_order_number匹配后直接更新原模型的对应字段即可。
2. 订单条目是否需要单独建模型?用JSON Field还是拆分模型?
建议拆分出单独的订单条目模型,不推荐用JSON Field存储整个订单,具体分析如下:
为什么不推荐JSON Field?
- 数据可操作性差:查询特定字段或更新单个属性时,需要解析整个JSON,无法利用数据库索引优化性能。
- 数据无约束:数据库层面无法校验JSON内字段的类型和合法性,容易产生脏数据。
- 动态更新繁琐:更新
accepted_quantity这类字段时,需要先读取整个JSON修改再重新写入,不如直接更新数据库字段高效。
模型拆分方案
将订单拆分为订单头(存储订单级公共属性)和订单条目(存储单个商品的明细属性)两个模型:
class VendorOrderHeader(models.Model): # 订单级公共属性 purchase_order_number = models.CharField(max_length=30, unique=True) purchase_order_state = models.CharField(max_length=30, default="", null=True, blank=True) purchase_order_date = models.DateTimeField() last_updated_date = models.DateTimeField(null=True, blank=True) window_start = models.DateTimeField(null=True, blank=True) window_end = models.DateTimeField(null=True, blank=True) selling_party = models.CharField(max_length=100) warehouse = models.CharField(max_length=100) class VendorOrderItem(models.Model): # 订单条目明细属性 order_header = models.ForeignKey(VendorOrderHeader, on_delete=models.CASCADE, related_name='items') item_sequence_number = models.IntegerField() buyer_product_identifier = models.CharField(max_length=30, default="", null=True, blank=True) vendor_product_identifier = models.CharField(max_length=30, default="", null=True, blank=True) ordered_quantity = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True) accepted_quantity = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True) received_quantity = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True) net_cost = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True) net_cost_currency = models.CharField(max_length=10, default="", null=True, blank=True) total_cost = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True) class Meta: unique_together = ('order_header', 'item_sequence_number') # 保证同一订单下的条目唯一
动态更新实现
定时任务调用API获取更新数据时:
- 通过
purchase_order_number找到对应的VendorOrderHeader实例 - 以
order_header+item_sequence_number为匹配条件,调用update_or_create方法,精准更新VendorOrderItem的目标字段(如accepted_quantity) - 可给
VendorOrderItem添加last_updated_date字段,每次更新时自动设置为当前时间,便于跟踪变更记录
内容的提问来源于stack exchange,提问作者Krapi
相关产品推荐
相关产品推荐

