Django - применение уникальных предметов ManyToManyField - PullRequest
21 голосов
/ 02 февраля 2011

Я пытаюсь сделать что-то простое, как это:

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 () не работает тихо? Должен ли я просто проверить, содержится ли пользователь уже перед добавлением?

Спасибо!

Ответы [ 2 ]

28 голосов
/ 02 февраля 2011

Например, я бы не стал использовать num_members. Вместо этого вы можете проверить, сколько членов в mygroup.members.count(). Во-вторых, добавление участников более одного раза на самом деле не добавляет их более одного раза, так что все в порядке.

A ManyToManyField на Group для member, указывающей на User, реализовано с отдельной таблицей (что-то вроде group_group_users), которая имеет внешний ключ для Group и User. У пользователя может быть несколько групп, а в группе может быть несколько пользователей, но в 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.
15 голосов
/ 02 февраля 2011

Дублирующиеся пользователи не отображаются в утилите администратора.

Они не созданы.

Не работает ли add () без вывода сообщений?

Да.

Должен ли я просто проверить, содержится ли пользователь уже перед добавлением?

Да.Или вместо того, чтобы вручную подсчитывать пользователей, вы могли бы просто подсчитать для вас счет базы данных:

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

Это устраняет необходимость в поле num_members в реальной модели.

Также,Вы не должны использовать id в качестве имени параметра для своей функции.

...