I think I need to create a 'many-to-many generic relationship'.
我认为我需要创建一个“多对多的通用关系”。
I have two types of Participants:
我有两种类型的参与者:
class MemberParticipant(AbstractParticipant):
class Meta:
app_label = 'participants'
class FriendParticipant(AbstractParticipant):
"""
Abstract participant common information shared for all rewards.
"""
pass
These Participants can have 1 or more rewards of 2 different kinds (rewards model is from another app):
这些参与者可以得到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.
"""
So now I need to link these all up. This is how I was thinking of creating the relationship (see below) would this work, any issues you see?
现在我需要把这些都联系起来。这就是我想要建立关系的方法(见下文),你看到了什么问题吗?
Proposed linking model below:
提出连接模型如下:
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')
Note: I'm using Django 1.6
注意:我使用的是Django 1.6
2 个解决方案
#1
12
Your approach is exactly the right way to do it given your existing tables. While there's nothing official (this discussion, involving a core developer in 2007, appears not to have gone anywhere), I did find this blog post which takes the same approach (and offers it in a third-party library), and there's also a popular answer here which is similar, except only one side of the relationship is generic.
对于现有的表,您的方法是正确的方法。虽然没有什么官方的(这个讨论,包括一个核心开发人员,2007年似乎没有了任何地方),我确实发现这个博客以同样的方法(并提供第三方库),还有一个受欢迎的答案是相似的,除了只有一方的关系是通用的。
I'd say the reason this functionality has never made it into django's trunk is that while it's a rare requirement, it's fairly easy to implement using the existing tools. Also, the chance of wanting a custom "through" table is probably quite high so most end-user implementations are going to involve a bit of custom code anyway.
我想说的是,这个功能从未在django的主干中出现的原因是,虽然这是一个罕见的需求,但是使用现有的工具实现它是相当容易的。此外,需要自定义“通过”表的可能性可能很高,因此无论如何,大多数最终用户实现都需要一些自定义代码。
The only other potentially simpler approach would be to have base Participant and Reward models, with the ManyToMany relationship between those, and then use multi-table inheritance to extend these models as Member/Friend etc.
另一种可能更简单的方法是拥有基本的参与者和奖励模型,以及它们之间的许多tomany关系,然后使用多表继承将这些模型扩展为成员/朋友等。
Ultimately, you'll just need to weigh up the complexity of a generic relation versus that of having your object's data spread across two models.
最终,您只需要权衡一个泛型关系的复杂性与将对象的数据分散到两个模型之间的复杂性。
#2
7
Late reply, but I found this conversation when looking for a way to implement generic m2m relations and felt my 2 cents would be helpful for future googlers.
回复晚了,但我在寻找一种方法来实现通用的m2m关系时发现了这个对话,并且觉得我的2美分对未来的谷歌人是有帮助的。
As Greg says, the approach you chose is a good way to do it.
正如Greg所说,你选择的方法是一个很好的方法。
However, I would not qualify generic many to many as 'easy to implement using existing tools' when you want to use features such as reverse relations or prefetching.
但是,当您希望使用反向关系或预取等特性时,我不会将泛型定义为“使用现有工具很容易实现”。
The 3rd party app django-genericm2m is nice but has several shortcomings in my opinion (the fact that the 'through' objects are all in the same database table by default and that you don't have 'add' / 'remove' methods - and therefore bulk add/remove).
第三方应用django-genericm2m很好,但在我看来有几个缺点(“通过”对象默认都在同一个数据库表中,而且没有“添加”/“删除”方法——因此大量添加/删除)。
With that in view, because I needed something to implement generic many-to-many relations 'the django way' and also because I wanted to learn a little bit about django internals, I recently released django-gm2m. It has a very similar API to django's built-in GenericForeignKey and ManyToManyField (with prefetching, through models ...) and adds deletion behavior customisation. The only thing it lacks for the moment is a suitable django admin interface.
考虑到这一点,因为我需要一些东西来实现多对多关系的“django方法”,也因为我想了解一些关于django内部的知识,我最近发布了django-gm2m。它的API与django的内置GenericForeignKey和ManyToManyField(通过模型进行预取)非常相似,并添加了删除行为定制。目前它唯一缺少的是一个合适的django管理界面。
#1
12
Your approach is exactly the right way to do it given your existing tables. While there's nothing official (this discussion, involving a core developer in 2007, appears not to have gone anywhere), I did find this blog post which takes the same approach (and offers it in a third-party library), and there's also a popular answer here which is similar, except only one side of the relationship is generic.
对于现有的表,您的方法是正确的方法。虽然没有什么官方的(这个讨论,包括一个核心开发人员,2007年似乎没有了任何地方),我确实发现这个博客以同样的方法(并提供第三方库),还有一个受欢迎的答案是相似的,除了只有一方的关系是通用的。
I'd say the reason this functionality has never made it into django's trunk is that while it's a rare requirement, it's fairly easy to implement using the existing tools. Also, the chance of wanting a custom "through" table is probably quite high so most end-user implementations are going to involve a bit of custom code anyway.
我想说的是,这个功能从未在django的主干中出现的原因是,虽然这是一个罕见的需求,但是使用现有的工具实现它是相当容易的。此外,需要自定义“通过”表的可能性可能很高,因此无论如何,大多数最终用户实现都需要一些自定义代码。
The only other potentially simpler approach would be to have base Participant and Reward models, with the ManyToMany relationship between those, and then use multi-table inheritance to extend these models as Member/Friend etc.
另一种可能更简单的方法是拥有基本的参与者和奖励模型,以及它们之间的许多tomany关系,然后使用多表继承将这些模型扩展为成员/朋友等。
Ultimately, you'll just need to weigh up the complexity of a generic relation versus that of having your object's data spread across two models.
最终,您只需要权衡一个泛型关系的复杂性与将对象的数据分散到两个模型之间的复杂性。
#2
7
Late reply, but I found this conversation when looking for a way to implement generic m2m relations and felt my 2 cents would be helpful for future googlers.
回复晚了,但我在寻找一种方法来实现通用的m2m关系时发现了这个对话,并且觉得我的2美分对未来的谷歌人是有帮助的。
As Greg says, the approach you chose is a good way to do it.
正如Greg所说,你选择的方法是一个很好的方法。
However, I would not qualify generic many to many as 'easy to implement using existing tools' when you want to use features such as reverse relations or prefetching.
但是,当您希望使用反向关系或预取等特性时,我不会将泛型定义为“使用现有工具很容易实现”。
The 3rd party app django-genericm2m is nice but has several shortcomings in my opinion (the fact that the 'through' objects are all in the same database table by default and that you don't have 'add' / 'remove' methods - and therefore bulk add/remove).
第三方应用django-genericm2m很好,但在我看来有几个缺点(“通过”对象默认都在同一个数据库表中,而且没有“添加”/“删除”方法——因此大量添加/删除)。
With that in view, because I needed something to implement generic many-to-many relations 'the django way' and also because I wanted to learn a little bit about django internals, I recently released django-gm2m. It has a very similar API to django's built-in GenericForeignKey and ManyToManyField (with prefetching, through models ...) and adds deletion behavior customisation. The only thing it lacks for the moment is a suitable django admin interface.
考虑到这一点,因为我需要一些东西来实现多对多关系的“django方法”,也因为我想了解一些关于django内部的知识,我最近发布了django-gm2m。它的API与django的内置GenericForeignKey和ManyToManyField(通过模型进行预取)非常相似,并添加了删除行为定制。目前它唯一缺少的是一个合适的django管理界面。