Django 多对多关系及中介表

11 投票
2 回答
18356 浏览
提问于 2025-04-15 13:45

我想记录哪个用户邀请了另一个用户加入一个群组……但是Django告诉我这样做会产生歧义,并且不符合规则(这也说得通)。

groups.group: 中介模型 Group_to_Member对User有多个外键,这样会造成歧义,是不被允许的。

那么我该怎么正确地做呢?也许可以用通用关系?但感觉有点复杂……这是我之前的思路(去掉了一些无关的部分)

from django.contrib.auth.models import User

class UserGroup(models.Model):
    members = models.ManyToManyField(User, through='Group_to_Member')

class UserGroup_to_Member(models.Model):
    group = models.ForeignKey(UserGroup)
    member = models.ForeignKey(User)

    invited_by = models.ForeignKey(User, related_name="group_invited_users")

解决方案

好的,我结合了大家提供的答案(谢谢大家!)以及我在网上找到的一些资料,再加上我自己不太高明的Python技能,做了一些尝试:

from django.contrib.auth.models import User

class UserGroup(models.Model):
    # notice there is no member object here
    ... other model data

    def add_member(self, **kwargs):
        g2m = UserGroup_to_Member(group = self,  **kwargs)
        g2m.save()

    def remove_member(self, member):
        g2m = UserGroup_to_Member.objects.get(group=self, member=member)
        g2m.delete()

    # This is not elegant at all, help please? I'm pretty sure it isn't
    # as bad on the database as it looks though.
    def get_members(self):
        g2ms = UserGroup_to_Member.objects.filter(group=self)
        member_ids = [g2m.member.id for g2m in g2ms]
        members = User.objects.none()
        for id in member_ids:
            members = members | User.objects.get(id=id)
        return members

class UserGroup_to_Member(models.Model):
    group = models.ForeignKey(UserGroup)
    member = models.ForeignKey(User)

    invited_by = models.ForeignKey(User, related_name="group_invited_users")

2 个回答

1

如果你在使用Django 1.7的话,这是可能的。

根据文档:https://docs.djangoproject.com/en/1.7/topics/db/models/#extra-fields-on-many-to-many-relationships

在Django 1.6及之前的版本中,很多对很多的关系中,包含多个外键的中间模型是被禁止的。

9

你需要自己来管理这个:

class MyGroup(models.Model):
    name = models.CharField(max_length=100)

class Membership(models.Model):
    group = models.ForeignKey(MyGroup)
    member = models.ForeignKey(User)

    invited_by = models.ForeignKey(User, related_name='invited_set')

所以你应该用 group.membership_set.all() 来代替 group.members.all()

另外,我建议你不要把模型命名为 'Group',因为Django已经有一个叫做Group的对象了。

撰写回答