【问题标题】:Django - enforcing ManyToManyField unique itemsDjango - 强制执行 ManyToManyField 唯一项
【发布时间】:2011-06-19 17:56:16
【问题描述】:

我正在尝试做这样简单的事情:

members = models.ManyToManyField(User, blank=True, null=True, unique=True)

但不允许唯一。当查看创建的表时,它会生成外键,因此我想这是暗示了唯一性。

我希望能够将成员与这个代表一个组的模型相关联。该组可以没有成员,但我不希望同一个成员能够加入该组两次。

我的想法是,如果我尝试这样做会引发异常,但似乎没有引发异常。

def join(request,id):
    user = request.user
    mygroup = Group.objects.get(id=id)
    mygroup.members.add(user)
    mygroup.num_members += 1
    mygroup.save()

num_members 递增,因为没有抛出异常。重复用户不会出现在管理实用程序中。 add() 会默默失败吗?我是否应该在添加之前简单地检查用户是否已经包含在内?

【问题讨论】:

  • 为什么不做一个从组到用户的外键?这样,一个用户可以在多个组中,但每个组只能出现一次 - 这就是您想要的。
  • 从组到用户的ForeignKey 表示组中只有一个用户。 ForeignKey 是多对一的。

标签: python django django-models


【解决方案1】:

首先,我不会使用num_members。相反,您可以使用mygroup.members.count() 检查有多少成员。其次,多次添加成员并不会真正添加多次,所以你很好。

Group 上的 Group 上的 member 指向 User 是通过一个单独的表(类似于 group_group_users)实现的,该表具有指向 GroupUser 的外键。一个用户可以有多个组,一个组可以有多个用户,但group_group_users中不能有两行同一个关系(即外键唯一)。

用法:

>>> group = Group.objects.get(pk=1)
>>> user = User.objects.get(pk=1)
>>> group.members.add(user)
>>> # Worked fine as expected. Let's check the results.
>>> group.members.all()
[<User: foousername>]
>>> group.members.add(user)
>>> # Worked fine again. Let's check for duplicates.
>>> group.members.all()
[<User: foousername>]
>>> # Worked fine.

【讨论】:

  • 这就是我要找的。为什么我不应该使用 id?
  • @JPC - 你可以,但最好使用pk。它映射到主键,无论你的主键是id还是identity
  • @JPC - 哦,那个id。不应该使用id 作为方法参数的原因是id 是一个内置的Python 函数。
  • @JPC 那么你将如何启用对同一个对象的多个引用呢?当然,在您的示例中不明智,但无论如何?
  • 好的,找到了。必须创建一个连接表。见:stackoverflow.com/questions/2350855/…
【解决方案2】:

重复用户不会出现在管理实用程序中。

它们不是被创造出来的。

add() 是否静默失败?

是的。

我是否应该在添加之前简单地检查用户是否已经包含在内?

是的。或者,您可以只为您计算数据库,而不是手动计算用户数:

mygroup = Group.objects.filter(...).annotate(num_members=models.Count("members"))

这消除了在实际模型中对num_members 字段的需求。

此外,您不应使用 id 作为函数的参数名称。

【讨论】:

  • P.S. mygroup.members.count() 运行单个 SQL 查询以获取计数 (SELECT COUNT(*) FROM ...),而我展示的 annotate 方法允许您使用 Group.objects.filter(...) 一次查询多个组并获取每个组的成员计数,所有这些都在一个 SQL 中查询而不是每组一个。并且有一个名为id的参数隐藏了同名的内置函数。
  • 检查用户是否已经被包含由于并发性而不能保证工作
  • 一般情况下是正确的,事先检查并不能消除捕获错误的需要。如果您将同时使用管理员,这很重要。如果是这样,您将不得不做一些思考来解决诸如“如果一个用户将某人添加到他们已经在的组中,但与此同时另一个用户从所述组中删除该某人,如果某人在组还是不组?”恕我直言,答案是“没关系;这是用户级别的协调失败,每个可能的结果仅对一个用户是正确的。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-10
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多