【问题标题】:Django many-to-many generic relationshipDjango 多对多泛型关系
【发布时间】:2013-11-04 16:52:41
【问题描述】:

我认为我需要创建“多对多通用关系”。

我有两种参与者:

class MemberParticipant(AbstractParticipant):
    class Meta:
        app_label = 'participants'


class FriendParticipant(AbstractParticipant):
    """
    Abstract participant common information shared for all rewards.
    """
    pass

这些参与者可以有 1 种或多种 2 种不同类型的奖励(奖励模型来自另一个应用程序):

class SingleVoucherReward(AbstractReward):
    """
    Single-use coupons are coupon codes that can only be used once
    """
    pass

class MultiVoucherReward(AbstractReward):
    """
    A multi-use coupon code is a coupon code that can be used unlimited times.
    """

所以现在我需要将这些都链接起来。这就是我想建立这种关系的方式(见下文)这是否可行,你看到任何问题吗?

建议的链接模型如下:

class ParticipantReward(models.Model):


    participant_content_type = models.ForeignKey(ContentType, editable=False,
                                                        related_name='%(app_label)s_%(class)s_as_participant',
                                                        )
    participant_object_id = models.PositiveIntegerField()
    participant = generic.GenericForeignKey('participant_content_type', 'participant_object_id')


    reward_content_type = models.ForeignKey(ContentType, editable=False,
                                                        related_name='%(app_label)s_%(class)s_as_reward',
                                                        )
    reward_object_id = models.PositiveIntegerField()
    reward = generic.GenericForeignKey('reward_content_type', 'reward_object_id')

注意:我使用的是 Django 1.6

【问题讨论】:

  • 我个人更喜欢使用 ForeignKey 而不是 GenericForeignKey 来获得通过 ORM 获得的额外功能。
  • @schillingt 感谢您的回复。奖励可以是 SingleVoucherReward 或 MultiVoucherReward,参与者可以是 MemberParticipant 或 FriendParticipant。这意味着如果我选择标准 FK,我需要 4 个 FK,其中两个总是空白。这对我来说是糟糕的数据库设计,所以我认为 GenericForeignKey 更有意义,但我愿意接受建议。我对您的评论“获得了额外的功能”感兴趣,您使用 GenericForeignKey 会失去什么?
  • 您不能再在过滤器或排除中使用这些字段。在docs 的本节底部提到了它。
  • 当然我仍然可以通过参与者对象直接在 ParticipantReward 上搜索?
  • 当然可以,只是稍微复杂一些,因为您必须同时过滤participant_content_type 和participant_object_id,而不是单个对象。

标签: python django django-models


【解决方案1】:

鉴于您现有的表格,您的方法正是正确的方法。虽然没有任何官方消息(this discussion,涉及 2007 年的核心开发人员,似乎没有去任何地方),我确实找到了这个 blog post,它采用了相同的方法(并在第三方库中提供),并且有也是一个流行的答案here,它是相似的,除了关系的一侧是通用的。

我想说这个功能从未进入 django 的主干的原因是,虽然它是一个罕见的需求,但使用现有工具实现它相当容易。此外,想要自定义“直通”表的可能性可能非常高,因此大多数最终用户实现无论如何都会涉及一些自定义代码。

唯一可能更简单的方法是拥有基础参与者和奖励模型,它们之间具有多对多关系,然后使用multi-table inheritance 将这些模型扩展为会员/朋友等。

最终,您只需权衡通用关系的复杂性与将对象数据分布在两个模型中的复杂性。

【讨论】:

  • 感谢Greg的回复,你链接的第三方库看起来很有意思。
【解决方案2】:

回复晚了,但我在寻找实现通用 m2m 关系的方法时发现了这个对话,并且觉得我的 2 美分对未来的谷歌员工会有帮助。

正如 Greg 所说,您选择的方法是一种很好的方法。

但是,当您想要使用反向关系或预取等功能时,我不会将通用多对多定义为“易于使用现有工具实现”。

第 3 方应用程序 django-genericm2m 不错,但在我看来有几个缺点(事实上,“通过”对象默认都在同一个数据库表中,并且您没有“添加”/“删除” ' 方法 - 因此批量添加/删除)。

考虑到这一点,因为我需要一些东西来实现通用的多对多关系“django 方式”,而且因为我想了解一些关于 django 内部结构的知识,所以我最近发布了django-gm2m。它具有与 django 的内置 GenericForeignKey 和 ManyToManyField 非常相似的 API(具有预取,通过模型......)并添加了删除行为自定义。它目前唯一缺少的是合适的 django 管理界面。

【讨论】:

    猜你喜欢
    • 2019-05-09
    • 2018-01-04
    • 2012-07-22
    • 2015-02-03
    • 2012-02-26
    • 1970-01-01
    相关资源
    最近更新 更多