我认为我需要创建一个'多对多通用关系'。
我有两种类型的参与者:
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
答案 0 :(得分:14)
根据您现有的表格,您的方法是正确的方法。虽然没有任何官方(this discussion,涉及2007年的核心开发人员,似乎没有去过任何地方),但我确实发现这个blog post采用相同的方法(并在第三方库中提供) ),并且还有一个类似的流行答案here,除了关系的一方是通用的。
我说这个功能从未进入django主干的原因是虽然这是一个罕见的要求,但使用现有工具实现起来相当容易。此外,想要一个自定义“通过”表的机会可能相当高,所以大多数最终用户实现无论如何都将涉及一些自定义代码。
唯一的另一种可能更简单的方法是使用基本参与者和奖励模型,并在这些模型之间使用ManyToMany关系,然后使用multi-table inheritance将这些模型扩展为成员/朋友等。
最终,您只需要权衡一般关系的复杂性与将对象的数据分布在两个模型中的复杂性。
答案 1 :(得分:8)
迟到的回复,但我在寻找实现通用m2m关系的方法时找到了这个对话,觉得我的2美分对未来的google有用。
正如格雷格所说,你选择的方法是一种很好的方法。
但是,当您想要使用反向关系或预取等功能时,我不会将许多通用限定为“使用现有工具易于实现”。
第三方应用程序django-genericm2m很不错,但在我看来有几个缺点(默认情况下'through'对象都在同一个数据库表中而且你没有'add'/'remove '方法 - 因此批量添加/删除)。
考虑到这一点,因为我需要一些东西来实现通用的多对多关系'django方式',而且因为我想学习一些django内部,我最近发布了django-gm2m。它与django的内置GenericForeignKey和ManyToManyField(具有预取,通过模型......)具有非常相似的API,并添加了删除行为定制。它目前唯一缺少的是一个合适的django管理界面。