Отношения "многие ко многим" в Django
Я пытаюсь создать веб-приложение, в котором пользователи могут участвовать в некоторых группах (каждый пользователь может быть частью нескольких групп), и я хочу иметь возможность делать запросы типа
group.users_set()
и
user.groups_set()
Я хочу видеть все группы, в которых участвует пользователь, на странице администратора каждого пользователя и наоборот. Моя последняя попытка была такой:
class CustomUser(AbstractUser):
groups = models.ManyToManyField('Group', through='Participation')
class Group(models.Model):
group_name = models.CharField(max_length=200)
group_password = models.CharField(max_length=200)
customusers = models.ManyToManyField('CustomUser', through='Participation')
class Participation(models.Model):
customuser = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
но я получаю
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:
ERRORS:
<class 'userreg.admin.CustomUserAdmin'>: (admin.E013) The value of 'fieldsets[2][1]["fields"]' cannot include the ManyToManyField 'groups', because that field manually specifies a relationship model.
Раньше, только
users = models.ManyToManyField(CustomUser)
в классе "Группа" и без класса "Участие" я смог добиться половины своей цели - увидеть список зарегистрированных пользователей на странице администратора. Что я делаю неправильно?
Вы указываете ManyToManyField в одной из двух моделей, поэтому, например:
class CustomUser(AbstractUser):
groups = models.ManyToManyField(
'Group',
related_name='users'
through='Participation'
)
class Group(models.Model):
name = models.CharField(max_length=200)
password = models.CharField(max_length=200)
class Participation(models.Model):
customuser = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
Параметр related_name=… [Django-doc] задает имя отношения в обратном порядке, то есть от Group к CustomUser, и вы можете переименовать его в users, как это сделано здесь. Если вы не укажете его, по умолчанию будет modelname_set с modelname именем модели (здесь CustomUser) в нижнем регистре (так customuser).
Поскольку ваша through=… модель [Django-doc] имеет только два ForeignKey к двум моделям, вам не нужно создавать одну, и вы можете упростить это до:
class CustomUser(AbstractUser):
groups = models.ManyToManyField(
'Group',
related_name='users'
)
class Group(models.Model):
name = models.CharField(max_length=200)
password = models.CharField(max_length=200)
Ответ, предоставленный @Willem Van Onsem, был очень полезен, но я решил свою проблему, сделав это в models.py
class CustomUser(AbstractUser):
groups = models.ManyToManyField('Group')
class Group(models.Model):
name = models.CharField(max_length=200)
password = models.CharField(max_length=200)
users = models.ManyToManyField(CustomUsers)
и это в admin.py:
from django.contrib import admin
from .models import Group, CustomUser
from django.contrib.auth.admin import UserAdmin
class GroupAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['group_name', 'group_password']}),
('Users', {'fields': ['users']}),
]
class CustomUserAdmin(UserAdmin):
fieldsets = [
(None, {'fields': ['username', 'password']}),
('Groups', {'fields': ['groups']}),
]
admin.site.register(CustomUser, CustomUserAdmin)
admin.site.register(Group, GroupAdmin)