I'm trying to create a web app in which users can participate in some groups (every user can be part of multiple groups), and I want to be able to make both queries like
group.users_set()
and
user.groups_set()
I want to see all groups a user is participating to in the admin page of every user and vice versa. My last attempt was this:
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)
but I get
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.
Before, with just
users = models.ManyToManyField(CustomUser)
in the Group class and without the Participation class, I was able to get half of my goal, seeing the list of logged users in the admin page. What am I doing wrong?
CodePudding user response:
You specify a ManyToManyField
in one of the two models, so for example:
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)
The related_name=…
parameter [Django-doc] specifies the name of the relation in reverse, so from Group
to CustomUser
, and you thus can rename this to users
as is here the case. If you do not specify one, the default is modelname_set
with modelname
the name of the model (here CustomUser
) in lowercase (so customuser
).
Since your through=…
model [Django-doc] only has two ForeignKey
s to the two models, you do not need to create one, and you can simplify this further to:
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)
CodePudding user response:
The answer provided by @Willem Van Onsem was very useful, but I solved my problem doing this in 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)
and this in 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)