Django销售活动模型的外键列表,只能出现在一个销售活动?



我想创建一个销售活动,其中存储图书列表(Items)。但这本书应该只适用于一次销售活动。它不能同时出现在两个广告系列中。

我有以下模型:

class Campaign(models.Model):
campaign_name = models.CharField(max_length=50, null=False, blank=False, default='Special Offer')
included_items = models.ManyToManyField(Item, blank=True)
active = models.BooleanField(default=True)
fixed_price = models.DecimalField(max_digits=6, blank=True, null=True, decimal_places=2)

但是我认为included_items字段可能是错误的字段类型。从阅读其他问题和Django手册来看,我想我可能会从头到尾地接近这个问题。也许我应该从项目模型来解决这个问题?(如下图供参考)

class Item(models.Model):
sku = models.CharField(
max_length=10, null=True, blank=True, 
default=create_new_sku)
title = models.CharField(max_length=254)
genre = models.ManyToManyField('Genre', blank=True)
author = models.ManyToManyField('Author', blank=True)
description = models.TextField()
age_range = models.ManyToManyField(
'Age_range')
image_url = models.URLField(max_length=1024, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
price = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
discount = models.DecimalField(max_digits=2, decimal_places=0, default=0)
set_sale_price = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
original_sale_price = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
final_price = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=False, editable=False)

如果每个item只能属于一个campaign,你应该在item模型中使用ForeignKey来创建多对一关系

其实你的设计还不错。

Item模型上使用@Henty的答案中的ForeignKey仍然会遇到问题,如果活动变得不活跃(active=False),Item模型需要取消ForeignKey以允许其他活动提供它。此外,Item模型的数据应该只包含关于该实例的信息。对我来说,我认为在Item模型中有一个外键是很奇怪的,因为这些数据与一本书无关。你可能需要阅读数据规范化。

也就是说,你应该手动指定你的多对多中间表,因为你需要在其中应用一个唯一的约束,这样只有一个活动活动可以提供这本书。

这个中间表也将有字段,如discountsale_price的书,因为不同的活动可以提供不同的折扣/价格。我假设你的Item模型中的price是你书上的基本零售价格,所以不需要discount,set_sale_price,original_sale_pricefinal_price-再次,参考数据归一化。

此外,您需要将active字段从Campaign实例复制到中间表,因为它将用于唯一约束。这是通过覆盖中间表上的save方法来复制Campaign实例的active值来完成的。

当你激活/停用一个活动时,你还必须覆盖Campaign模型上的save方法来更新中间实例上的active字段。

class Campaign(models.Model):
campaign_name = ...
included_items = models.ManyToManyField(
Item,
through='CampaignItem',
through_fields=('campaign', 'item')
)
active = ...
fixed_price = ...
def save(self, *args, **kwargs):
# pre-save, update associated campaign-item instances
CampaignItem.objects.filter(campaign=self).update(active=self.active)
super().save(*args, **kwargs)

class CampaignItem(models.Model):
campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
active = models.BooleanField(editable=False)
discount = ...
sale_price = ...
# add any other relevant fields related to this campaign item
class Meta:
# add constraint where item can only be in one active campaign
constraints = [
UniqueConstraint(fields=['item'],
condition=Q(active=True),
name='unique_active_item')
]
def save(self, *args, **kwargs):
# copy over the `active` value from campaign
self.active = self.campaign.active
super().save(*args, **kwargs)

最新更新