Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django多对多字段拷贝_Python_Django_Django Models_Many To Many - Fatal编程技术网

Python Django多对多字段拷贝

Python Django多对多字段拷贝,python,django,django-models,many-to-many,Python,Django,Django Models,Many To Many,我有一个Django模型,有两个多对多字段。从管理界面保存模型时,我需要检查第二个字段是否为空,如果为空,则需要将第一个字段中的项目复制到第二个字段中。我该怎么做 更新 Matthew的答案似乎很有用,但在复制字段后,我无法保存实例。我尝试了instance.save(),但没有成功。您可以重写clean方法来执行额外的验证,因此如果第二个many2many为空,您可以设置默认值,例如: def clean(self): super(MyClassModel, self).clean()

我有一个Django模型,有两个多对多字段。从管理界面保存模型时,我需要检查第二个字段是否为空,如果为空,则需要将第一个字段中的项目复制到第二个字段中。我该怎么做

更新


Matthew的答案似乎很有用,但在复制字段后,我无法保存实例。我尝试了instance.save(),但没有成功。

您可以重写clean方法来执行额外的验证,因此如果第二个many2many为空,您可以设置默认值,例如:

def clean(self):
    super(MyClassModel, self).clean()

    if not self.MySecondMany2Many:
        # fill data
您应该在类中的models.py中设置此代码。如果由于需要保存模型而导致“清理”无法工作,则也可以覆盖“保存”功能,这是相同的过程


我还没有测试它,我不认为你可以通过这种方式检查多个字段是否为空,但你应该知道:)

你可以使用后期保存信号。这看起来可能是处理您的需求的最佳方式:好处是它也可以在管理员之外工作

@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中的信号。

要使用的信号不是
post\u save
,而是
m2m\u 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')
编辑:下一个代码更简单,并且基于关于模型定义的新知识

在您的代码中,“第一个”信号在“第二个”信号之前发送(这实际上取决于您的模型定义)。因此,我们可以假设当接收到“第二个”信号时,“第一个”已经填充了当前数据

这让我们更高兴,因为现在您只需检查m2m预添加:

@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))

您可以从这里看到定义,只需覆盖它并检查相关字段是否为空,如果为空,请保存对象,然后从第二个M2M获取相关数据,并将其设置为第一个M2M,然后再次保存…

Hmm。保存前使用M2M字段可能会导致很大的失败:它会尝试在有PK之前使用PK。然后您可以更好地覆盖保存。但是现在Matthew发布了关于post_save signals的文章,我同意这是一个更干净的问题解决方案。这似乎是一个很好的解决方案,但我无法在添加值后保存实例。我已经尝试过instance.save(),但它不起作用。有什么想法吗?保存后会发送post_save信号,但m2m insert队列已经完成,因此您不能在那里修改它。我通常使用python的pdb进行调试,以检查发生了什么,尝试放置一个导入pdb;pdb.set_trace()就在instance.save()行之前,然后按“s”键进入函数并查看发生了什么,然后按“n”键进入下一步。这是一个以防万一的例子,因为没有“添加前”和“添加后”。你是说“添加前”和“添加后”吗?当然可以。对不起,我会改正的。(更复杂的版本)这是我目前使用的一种方法,用于确保m2m的内容始终是另一个内容的子集(例如“已启用”和“活动”内容,其中必须启用活动,否则它们将被忽略)。这对我不起作用,我不明白为什么。我正在打印一些日志,我注意到missing_field_2在missing_field_1之前执行。然后,它继续抛出一个错误,表示未定义\uuu was\u empty。有什么想法吗?我写的代码逻辑中有几个错误。我现在就纠正它们。