gpt4 book ai didi

python - Django - 验证模型和 ModelForm 中计算字段的唯一性

转载 作者:行者123 更新时间:2023-11-30 22:15:49 25 4
gpt4 key购买 nike

TL;DR 我的模型和表单都会计算字段 number_as_char 的值。在使用没有表单的模型时,我可以避免双重工作,但仍然检查唯一性吗?

我使用 Python 3 和 Django 1.11

<小时/>

我的模型如下所示:

class Account(models.Model):
parent_account = models.ForeignKey(
to='self',
on_delete=models.PROTECT,
null=True,
blank=True)
number_suffix = models.PositiveIntegerField()
number_as_char = models.CharField(
max_length=100,
blank=True,
default='',
unique=True)

@classmethod
def get_number_as_char(cls, parent_account, number_suffix):
# iterate over all parents
suffix_list = [str(number_suffix), ]
parent = parent_account
while parent is not None:
suffix_list.insert(0, str(parent.number_suffix))
parent = parent.parent_account

return '-'.join(suffix_list)

def save(self, *args, **kwargs):
self.number_as_char = self.get_number_as_char(
self.parent_account, self.number_suffix)
super().save(*args, **kwargs)

字段number_as_char不应由用户设置,因为它是根据所选parent_account计算的:它是通过链接字段的值获得的所有父帐户和当前实例的 code>number_suffix

这是一个包含三个帐户的示例:

ac1 = Account()
ac1.parent_account = None
ac1.number_suffix = 2
ac1.save()
# ac1.number_as_char is '2'

ac2 = Account()
ac2.parent_account = ac1
ac2.number_suffix = 5
ac2.save()
# ac2.number_as_char is '2-5'

ac3 = Account()
ac3.parent_account = ac2
ac3.number_suffix = 1
ac3.save()
# ac3.number_as_char is '2-5-1'

不是删除该字段并使用模型属性的选项,因为我需要确保唯一性,并使用该字段通过order_by()对查询集进行排序>.

<小时/>

我的表单如下所示:

class AccountForm(forms.ModelForm):

class Meta:
model = Account
fields = [
'parent_account', 'number_suffix', 'number_as_char',
]
widgets = {
'number_as_char': forms.TextInput(attrs={'readonly': True}),
}

def clean(self):
super().clean()
self.cleaned_data['number_as_char'] = self.instance.get_number_as_char(
self.cleaned_data['parent_account'], self.cleaned_data['number_suffix'])

我在带有小部件属性readonly的表单中包含了number_as_char,并使用表单clean()方法来计算number_as_char (必须在验证唯一性之前计算)。

<小时/>

这一切都有效(模型和表单),但验证表单后,模型 save() 方法将再次计算 number_as_char 的值。这不是一个大问题,但是有没有办法避免这种双重计算?

  1. 如果我从表单 clean() 方法中删除计算,则不会使用新值验证唯一性(它只会检查旧值)。
  2. 我不想从模型中完全删除计算,因为我在其他部分使用模型而不使用表单。

您有什么建议可以采取不同的方式来避免字段的重复计算吗?

最佳答案

考虑到您需要它用于非表单,我看不到在两个地方(save()clean())执行此操作的任何方法基于的保存也是如此)。

不过,我可以为您的 get_number_as_char 方法提供两项效率改进:

  1. 将其设为 cached_property这样第二次调用时,您只需返回一个缓存值并消除重复计算。显然,您需要注意在更新实例之前不要调用此函数,否则旧的 number_as_char 将被缓存。只要仅在保存/清理期间调用 get_number_as_char() 就应该没问题。

  2. 根据您上面提供的信息,您不必迭代所有祖先,而只需获取父级的 number_as_char 并附加到它。

以下内容包含两者:

@cached_property
def get_number_as_char(self, parent_account, number_suffix):
number_as_char = str(number_suffix)
if parent_account is not None:
number_as_char = '{}-{}'.format(parent_account.number_as_char, number_as_char)

return number_as_char

为了确保缓存不会导致问题,您可以在保存完成后清除缓存的值:

def save(self, *args, **kwargs):
self.number_as_char = self.get_number_as_char(
self.parent_account, self.number_suffix)
super().save(*args, **kwargs)
# Clear the cache, in case something edits this object again.
del self.get_number_as_char

关于python - Django - 验证模型和 ModelForm 中计算字段的唯一性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50179154/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com