Opened 6 years ago

Closed 5 years ago

#29019 closed Bug (fixed)

createsuperuser crashes if a ManyToManyField is in REQUIRED_FIELDS

Reported by: James Kirsop Owned by: Hasan Ramezani
Component: contrib.auth Version: dev
Severity: Normal Keywords: user custom
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I've defined a custom user model with a ManyToMany field.

When running manage.py createsuperuser I receive the following error after entering the user's email address:

Traceback (most recent call last):
  File "./manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/jkirsop/Development/artemis/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "/Users/jkirsop/Development/artemis/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 365, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/jkirsop/Development/artemis/venv/lib/python3.6/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/jkirsop/Development/artemis/venv/lib/python3.6/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 59, in execute
    return super().execute(*args, **options)
  File "/Users/jkirsop/Development/artemis/venv/lib/python3.6/site-packages/django/core/management/base.py", line 335, in execute
    output = self.handle(*args, **options)
  File "/Users/jkirsop/Development/artemis/venv/lib/python3.6/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 133, in handle
    ) if field.remote_field else '',
AttributeError: 'ManyToManyRel' object has no attribute 'field_name'

Models
My custom user model is defined as such (relevant pieces only included):

class OrgUser(AbstractBaseUser, PermissionsMixin):
	email = models.EmailField(
		verbose_name='email address',
		max_length=255,
		unique=True,
	)
	orgs = models.ManyToManyField(Organisation)
	USERNAME_FIELD = 'email'
	REQUIRED_FIELDS = ['orgs']
        objects = OrgUserManager()

and Organisations

class Organisation(models.Model):
	name = models.CharField(max_length=60)

	def __str__(self):
		return self.name

It seems that if I remove the need for the Orgs to be a REQUIRED_FIELD the issue goes away. However, it's central to my project and needs to be defined on every user.

Happy to update the ticket with any other code snippets if required.

Change History (9)

comment:1 by Tim Graham, 6 years ago

Summary: Superuser creation for custom user model fails with required ManyToMany fieldcreatesuperuser crashes if a ManyToManyField is in REQUIRED_FIELDS
Triage Stage: UnreviewedAccepted

comment:2 by Sergey Yurchenko, 6 years ago

REQUIRED_FIELDS is field special for createsuperuser command. https://docs.djangoproject.com/en/2.0/topics/auth/customizing/#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS

In your forms or API this field would be still required if you remove it from REQUIRED_FIELDS
I don`t think there is a good way to set m2m fields during creation if superuser

comment:3 by Tim Graham, 6 years ago

Similar to foreign keys, ids could be accepted for ManyToManyFields. In the case of a through model, a helpful error message could be displayed indicating that it's not supported. In any case, Django shouldn't crash without a helpful message.

comment:4 by Williams Mendez, 6 years ago

Owner: changed from nobody to Williams Mendez
Status: newassigned

comment:5 by Lenno Nagel, 6 years ago

Hi!

We explored a couple of ideas regarding this during DjangoCon Europe 2018.

The aspect that blocks implementation is the create_superuser function in the default UserManager class that has no support for M2M field data present in kwargs. Such data would have to be extracted from kwargs and handled after the user.save(..) call, however we did not feel comfortable with proposing code for this solution without prior discussion.

It was found that it is perhaps best simply to warn the user whenever M2M fields have been added to REQUIRED_FIELDS and suggest that in this case, a custom user manager must also be written that handles the data properly. We could not find a safe way to detect whether the default manager has been overridden or whether it would handle the M2M field in the create_superuser function, so this warning has to be marked as ignored manually by the user.

A proposed solution:
https://github.com/django/django/pull/9990

Regards,
Lenno

Last edited 6 years ago by Lenno Nagel (previous) (diff)

comment:6 by Hasan Ramezani, 5 years ago

Has patch: set
Owner: changed from Williams Mendez to Hasan Ramezani
Version 0, edited 5 years ago by Hasan Ramezani (next)

comment:7 by Mariusz Felisiak, 5 years ago

Patch needs improvement: set
Version: 2.0master

comment:8 by Hasan Ramezani, 5 years ago

Patch needs improvement: unset

comment:9 by Mariusz Felisiak <felisiak.mariusz@…>, 5 years ago

Resolution: fixed
Status: assignedclosed

In 03dbdfd9:

Fixed #29019 -- Added ManyToManyField support to REQUIRED_FIELDS.

Note: See TracTickets for help on using tickets.
Back to Top