Django OneToOne 字段到自我

Posted

技术标签:

【中文标题】Django OneToOne 字段到自我【英文标题】:Django OneToOne field to self 【发布时间】:2016-11-10 16:44:07 【问题描述】:

如何定义OneToOne与同一个Model的关系?

我有一个名为Order 的模型,它可以与另一个模型Order 配对。现在我试图弄清楚如何处理这种关系的模型。

我的想法:

class Order(models.Model):
    paired_order = models.OneToOneField(self)

或者:

class Pairing(models.Model):
    order1 = models.ForeignKey(Order, related_name='pairing')
    order2 = models.ForeignKey(Order, related_name='pairing')

你怎么看?哪个更有效率?

我想简单地调用配对的。所以我会做这样的事情:

order.paired_order 

或者:

order.pairing.paired

我希望这种关系是对称的,所以对于每一对订单我都调用相同的东西并得到成对的订单。

配对模型将是一个很好的解决方案,因为我可以为这种关系添加额外的信息,但是有一个问题是我必须检测它是哪个顺序,所以我不能打电话给order.pairing.order1,因为我没有知道我是否没有调用相同的命令。

编辑:

>>> from _app import models
>>> order1 = models.Order(flight_number="xxx")
>>> order2 = models.Order(flight_number="yyy", paired_order=order1)
>>> order1.paired_order.flight_number

返回None object has not ....

问题是,当我将 order1 设置为 order2 的配对订单时,我想要相反方向的相同东西。所以order1.paired_order = order2 也这样做order2.paired_order = order1

【问题讨论】:

你在这里问什么?如何定义关系或哪个更好? Django self-referential relationship?的可能重复 Django-model: how to reference to self?的可能重复 Django self-referential foreign key的可能重复 为什么它与任何其他一对一关系的工作方式不同?您应该尝试使用这些重复项中的任何一个 【参考方案1】:

我自己也有这个问题,“对称”这个词是找到答案的关键:https://code.djangoproject.com/ticket/7689

class Order(models.Model):
    paired_order = models.OneToOneField(self)

def save(self, *args, **kwargs):
    super(Order, self).save(*args, **kwargs)
    self.paired_order.paired_order = self
    super(Order, self.paired_order).save()

【讨论】:

【参考方案2】:

配对模型将是一个很好的解决方案,因为我可以添加额外的 这种关系的信息。

在这种情况下,您可以为该组“订单”(您称之为配对)建模并添加一个快捷方式来检索配对订单。

class OrderPair(models.Model):
    pass        
    # additional information goes here


class Order(models.Model):
    pair = models.ForeignKey(to="OrderPair", related_name="orders")
    # you'll have to add custom validation 
    # to make sure that only 2 orders can belong to the same "OrderPair"

    @property
    def paired_order(self):
         return self.pair.orders.exclude(id=self.id).first()

完成此操作后,您可能还希望缓存配对订单以避免过多的查询。在这种情况下,您不需要相关名称,因此您可以使用 +(Django 中不太明确的东西)。

class Order(models.Model):
    ...
    cached_paired_order = models.ForeignKey(to='self', related_name='+')

@property
def paired_order(self):
     if self.cached_paired_order:
          ...
     else:
          ...

【讨论】:

【参考方案3】:

ForeignKey 不仅接受一个类作为参数,还接受 ForeignKey('ModelNameInSameModelsPyFile')ForeignKey('app_name.ModelName 形式的字符串名称。

在你的情况下,它可能是这样的

class Order(models.Model):

     paired = models.ForeignKey('Order', null=True)

您可以在https://docs.djangoproject.com/en/1.8/ref/models/fields/#foreignkey阅读更多内容

【讨论】:

或者直接使用"self" 好的,让我们有 order1 和 order2。现在当我做 order1.paired = order2 时,我可以这样调用 order1:order2.paired 吗?可能不是,这就是问题所在。 你可以有一个related_name,但我相信你不能叫它paired——你需要另一个名字。 视情况而定。如果配对是唯一的,即:一个订单只能与另一个订单配对,您可以使用OneToOneField (docs.djangoproject.com/en/1.8/ref/models/fields/#onetoonefield)。并且您需要设置related_name(但它不能是paired,可能是paired_to)。如果它不是唯一的,那么它可以被order2.<related_name>.filter(....)使用 它必须是独一无二的。一个订单有一个配对订单,反之亦然。

以上是关于Django OneToOne 字段到自我的主要内容,如果未能解决你的问题,请参考以下文章

ForeignKey vs OneToOne 字段 django [重复]

Django中的OnetoOne(primary_key = Tue)到ForeignKey

如何在 Django Admin 中更改 OneToOne 模型字段默认消息?

附加“_id”的OneToOne字段上的Django过滤器并失败

Django Admin:如何在 oneToOne 关系中的两个模型中显示带有 list_display 的字段值?

无法在 graphene_django 中获取 OneToOne 关系查询的值