sha*_*k3r 14 python django postgresql database-design django-models
我们公司的定价取决于多个参数,现在我们想为Django中的现有设置引入另一个可能的M2M参数。
为此,我们有一个现有的定价表,该表对unique_together
除之外的所有字段都有约束price_field
。在示例中为通用/基于字母的命名表示歉意。
class PricingTable(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE)
price = MoneyField()
b = ArrayField(models.CharField(choices=CHOICES))
c = models.ForeignKey(C, on_delete=models.CASCADE)
class Meta:
ordering = ("a",)
unique_together = ("a", "b", "c")
def validate_b(self):
# b can't be empty
if not len(self.b) >= 1:
raise ValueError
# each element in b needs to be unique
if not len(self.b) == len(set(self.b)):
raise ValueError
# each element in b needs to be unique together with a & c
for i in self.b:
query = PricingTable.objects.filter(
a=self.a, c=self.c, b__contains=[i]
).exclude(pk=self.pk)
if query.count() > 0:
raise ValueError
def save(self, *args, **kwargs):
self.validate_b()
return super().save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
我想向该表中引入另一个参数,该参数必须与非价格参数(a
,b
&c
)一起唯一。
d = models.ManyToManyField("x.D", related_name="+")
Run Code Online (Sandbox Code Playgroud)
列表中的每个元素b
都必须与a
&一起唯一c
。
上面的问题是,validate_b
必须通过繁重的数据库查询将功能升级为可能复杂的功能。Django并没有提供直接的方法来确保多对多字段的唯一性。
因此,我应该尝试使用其他方法吗?一个through
表吧?但是,我应该在穿透表中包括哪些所有字段?所有非价格字段?还是我应该停止梦想拥有众多领域,d
并继续采用简单的外键方法,并unique_together
在所有这些方面都直截了当?
版本:
如果需要,我可以将现有的ArrayField转换为简单的数组CharField
,这意味着会有更多的数据库行,只要我将所有唯一的约束都放入数据库中,而不是每次都进行保存验证,就可以了。
由于只有少数d
实体必须有相应的价格(其余实体将继续具有通用的共同价格),因此我最终采用了以下结构。
class PricingTable(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE)
price = MoneyField()
b = ArrayField(models.CharField(choices=CHOICES))
c = models.ForeignKey(C, on_delete=models.CASCADE)
d = models.ForeignKey("x.D", on_delete=models.CASCADE, blank=True, null=True)
class Meta:
ordering = ("a",)
unique_together = ("a", "b", "c", "d")
def validate_b(self):
# b can't be empty
if not len(self.b) >= 1:
raise ValueError
# each element in b needs to be unique
if not len(self.b) == len(set(self.b)):
raise ValueError
# each element in b needs to be unique together with a, c & d
query = PricingTable.objects.filter(
a=self.a, c=self.c, d=self.d, b__overlap=self.b
).exclude(pk=self.pk)
if query.count() > 0:
raise ValueError
def save(self, *args, **kwargs):
self.validate_b()
return super().save(*args, **kwargs)
class DBasedPricing(models.Model):
"""
Lookup table that tells (row exists) if we have D based pricing coupled with param A
If we do, query PricingTable.d=d, else PricingTable.d=None for correct pricing
"""
d = models.ForeignKey("x.D", on_delete=models.CASCADE)
a = models.ForeignKey(A, on_delete=models.CASCADE)
class Meta:
unique_together = ("d", "a")
Run Code Online (Sandbox Code Playgroud)
这迫使我首先根据参数进行查找d
,以检查定价是否D
基于
d_id = None
if DBasedPricing.objects.filter(d_id=input_param.d, a_id=a.id).exists():
d_id = input_param.d
Run Code Online (Sandbox Code Playgroud)
然后向我的常用查询添加另一个参数
price_obj = PricingTable.objects.filter(...usual query..., d_id=d_id)
Run Code Online (Sandbox Code Playgroud)
总的来说,以一次简单的索引查找为代价,我节省了行数,当然还有复杂的数据库结构。另外,我最终不必重新输入所有现有的定价!
归档时间: |
|
查看次数: |
334 次 |
最近记录: |