【问题标题】:How to automatically create symmetric object on Django's ManyToManyField?如何在 Django 的 ManyToManyField 上自动创建对称对象?
【发布时间】:2012-08-03 03:51:36
【问题描述】:

我想在我的模型上创建一个对称关系,并在关系中添加一个字段。我遇到了this blog(还有this another blog)并按照步骤创建了我自己的模型。

class CreditCardIssuer(models.Model):
    name = models.CharField(_('name'), max_length=256)
    transfer_limits = models.ManyToManyField('self', through='Balancetransfer', related_name='no_transfer_allowed+', symmetrical=False, help_text=_('List of issuers to which balance transfer is not allowed.'))

    def add_balancetransfer(self, creditcardissuer, until):
        balance_transfer, _newly_created = Balancetransfer.objects.get_or_create(
            no_transfer_from=self,
            no_transfer_to=creditcardissuer,
            until=until)
        balance_transfer, _newly_created = Balancetransfer.objects.get_or_create(
            no_transfer_from=creditcardissuer,
            no_transfer_to=self,
            until=until)
        return balance_transfer

    def remove_balancetransfer(self, creditcardissuer, until):
        Balancetransfer.objects.filter(
            no_transfer_from=self, 
            no_transfer_to=creditcardissuer,
            until=until).delete()
        Balancetransfer.objects.filter(
            no_transfer_from=self, 
            no_transfer_to=creditcardissuer,
            until=until).delete()
        return

    def get_transfer_limits(self, until):
        return self.transfer_limits.filter(
            no_transfer_to__until=until, 
            no_transfer_to__no_transfer_from=self)


class Balancetransfer(models.Model):
    no_transfer_from = models.ForeignKey('CreditCardIssuer', related_name='no_transfer_from')
    no_transfer_to = models.ForeignKey('CreditCardIssuer', related_name='no_transfer_to')
    until = models.IntegerField(blank=True, null=True, help_text='Minimum card ownership period to allow balance transfer.')

    class Meta:
        unique_together = ('no_transfer_from', 'no_transfer_to')

但是当我从管理员创建关系时,只创建了一个。你能帮我解决问题吗?

【问题讨论】:

  • 您能否详细说明一下您对only one is created 的含义?或者指定您期望发生的事情?
  • 函数 CreditCardIssuer.add_balancetransfer 显示了我从管理员创建关系时想要完成的任务。这样,将为两个对象创建关系。感谢您花时间解决它。
  • 不会“自动”创建两个关系——我不是 100% 清楚你所期望的行为。你能详细说明一下吗?
  • 没有魔法,IIRC,你需要调用balance_transfer 和remove_balancetransfer 或者明确地做get_or_create,例如在m2m_changed 的信号处理程序中。
  • 为什么不直接使用 symmetric=True m2m-to-self 字段,让 Django 为您完成对称工作?还是因为您想要until 字段?在这种情况下,您如何从管理员创建 m2m 关系? (管理员不会处理symmetric=False m2m-to-self 字段,对吗?)

标签: python django django-models django-admin


【解决方案1】:

你说你已经在 Django 管理中获得了一半(你没有说如何,但除非你发布代码,否则我会假设它可以工作):剩下的步骤是设置一半缺失的关系。

我怀疑如果你在 add_balancetransfer() 方法 (import pdb; pdb.set_trace()) 中放置一个断点,你会发现它永远不会被调用 - is 创建的关系部分是通过内置的 Django 管理行为完成。

简而言之,您可能只需要在保存模型时自己调用 add_balancetransfer() — 或者,更好的是,只添加缺失关系的不同版本。

一种方法是overriding the model's save() method,但这可能有点脆弱。对于您的情况,在model's post_save signal中填写缺失的关系可能会更好:

from django.db.models.signals import post_save
from django.dispatch import receiver

from yourapp.models import CreditCardIssuer

@receiver(post_save, sender=CreditCardIssuer)
def add_missing_relationship(sender, **kwargs):
    # Add the other side of what should be a symmetrical relationship
    ...

【讨论】:

  • 感谢您的建议。我已经在这些方法中添加了一些日志记录,并确认它们永远不会被调用。如果没有自动创建反向关系对象的方法,也许我会使用覆盖 save() 方法。
  • @supervacuo 看起来像是错字。您的导入用于 post_save,而您的接收者使用 pre_save。
猜你喜欢
  • 1970-01-01
  • 2015-03-31
  • 2018-02-11
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多