Django 多对多字段复制
我有一个Django模型,这个模型里有两个多对多的字段。当我从管理界面保存这个模型的时候,我需要检查第二个字段是否为空。如果第二个字段是空的,我就需要把第一个字段里的内容复制到第二个字段里。我该怎么做呢?
更新
Matthew的回答看起来很不错,但我在复制字段后无法保存这个实例。我尝试过使用instance.save(),但没有成功。
4 个回答
0
你可以重写clean方法来进行额外的验证,这样如果第二个多对多字段是空的,你可以设置默认值,比如:
def clean(self):
super(MyClassModel, self).clean()
if not self.MySecondMany2Many:
# fill data
你应该把这段代码放在你的models.py文件里,放在你的类里面。如果clean方法不起作用,因为模型需要被保存,你也可以重写save函数,步骤是一样的。
我没有测试过,我觉得你可能不能通过那种方式检查多对多字段是否为空,但你应该能明白这个意思 :)
3
你可以使用一个“保存后”的信号。这看起来是处理你需求的最佳方法,另外一个好处是它也可以在管理后台之外使用。
@models.signals.post_save(sender=MyModel)
def duplicate_missing_field(sender, instance, **kwargs):
if not instance.my_second_m2m.count():
instance.my_second_m2m.add(*instance.my_first_m2m.all())
# or *instance.my_first_m2m.values_list('pk', flat=True), I think
我的代码可能不是完全正确的:你需要了解一下Django中的信号。
4
这里要用的信号不是 post_save
,而是 m2m_changed
,这个信号是在模型保存到数据库后很久才会发送。
@models.signals.m2m_changed(sender=MyModel.second_m2m.through)
def duplicate_other_on_this_if_empty(sender, instance, action, reverse, model, pk_set, **kwargs):
# just before adding a possibly empty set in "second_m2m", check and populate.
if action == 'pre_add' and not pk_set:
instance.__was_empty = True
pk_set.update(instance.first_m2m.values_list('pk', flat=True))
@models.signals.m2m_changed(sender=MyModel.first_m2m.through)
def duplicate_this_on_other_if_empty(sender, instance, action, reverse, model, pk_set, **kwargs):
# Just in case the "first_m2m" signals are sent after the other
# so the actual "population" of the "second_m2m" is wrong:
if action == 'post_add' and not pk_set and getattr(instance, '__was_empty'):
instance.second_m2m = list(pk_set)
delattr(instance, '__was_empty')
补充说明:接下来的代码更简单,并且是基于对模型定义的新理解
在你的代码中,'first_m2m' 的信号是在 'second_m2m' 之前发送的(这实际上取决于你的模型定义)。所以我们可以假设,当收到 'second_m2m' 的信号时,'first_m2m' 已经填充了当前的数据。
这让我们更开心,因为现在你只需要检查 m2m-pre-add:
@models.signals.m2m_changed(sender=MyModel.second_m2m.through)
def duplicate_other_on_this_if_empty(sender, instance, action, reverse, model, pk_set, **kwargs):
# just before adding a possibly empty set in "second_m2m", check and populate.
if action == 'pre_add' and not pk_set:
pk_set.update(instance.first_m2m.values_list('pk', flat=True))