Opened 7 years ago

Last modified 7 months ago

#28608 new Cleanup/optimization

Allow UserCreationForm and UserChangeForm to work with custom user models

Reported by: Rômulo Collopy Owned by: shangdahao
Component: contrib.auth Version: dev
Severity: Normal Keywords: user, custom user, auth
Cc: Lemuel Formacil, Ülgen Sarıkavak Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

class UserChangeForm(forms.ModelForm):
    # ...
    class Meta:
        model = User

and

class UserCreationForm(forms.ModelForm):
    class Meta:
        model = User

could use UserModel instead of User. It is already defined in https://github.com/django/django/blob/01c6a3e227b645e8dea97e9befecd23d1d3b8581/django/contrib/auth/forms.py#L20 and is used in other forms of the same package.

This would allow Django Registration and other packages that use these forms to work out of the box. And it would allow using them with no need to rewitte as specified at https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#custom-users-and-the-built-in-auth-forms

Attachments (1)

patch.diff (2.2 KB ) - added by Rômulo Collopy 7 years ago.
patch

Download all attachments as: .zip

Change History (10)

by Rômulo Collopy, 7 years ago

Attachment: patch.diff added

patch

comment:1 by Tim Graham, 7 years ago

Patch needs improvement: set
Summary: UserCreationForm and UserChangeForm model using get_user_modelAllow UserCreationForm and UserChangeForm to work with custom user models

This is a continuation of #19353.

comment:2 by Tim Graham, 7 years ago

Triage Stage: UnreviewedAccepted

comment:3 by shangdahao, 7 years ago

Owner: changed from nobody to shangdahao
Patch needs improvement: unset
Status: newassigned

Since This ticket is related to ticket 28757, I made the changes for this ticket and ticket 28757 in the same commit.

PR

comment:4 by Tim Graham <timograham@…>, 7 years ago

Resolution: fixed
Status: assignedclosed

In 3333d93:

Fixed #28757 -- Allowed using contrib.auth forms without installing contrib.auth.

Also fixed #28608 -- Allowed UserCreationForm and UserChangeForm to
work with custom user models.

Thanks Sagar Chalise and Rômulo Collopy for reports, and Tim Graham
and Tim Martin for reviews.

comment:5 by Tim Graham, 6 years ago

Has patch: unset
Resolution: fixed
Status: closednew

In f3fa86a89b3b85242f49b2b9acf58b5ea35acc1f:

Fixed #29449 -- Reverted "Fixed #28757 -- Allowed using contrib.auth forms without installing contrib.auth."

This reverts commit 3333d935d2914cd80cf31f4803821ad5c0e2a51d due to a crash if USERNAME_FIELD isn't a CharField.

comment:6 by Lemuel Formacil, 6 years ago

Another non-standard behavior of the UserCreationForm when used with a custom user model is if the model has a ManyToManyField the form will not save the value of the ManyToManyField. From the documentation:

If your model has a many-to-many relation and you specify commit=False when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database.

To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After you’ve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data.

However, the UserCreationForm.save() method initially calls the form's save method with commit=False but then doesn't call the save_m2m method after committing the instance if commit=True. The save() method should be something like this so the form would behave as expected with custom user models with a many-to-many relation:

def save(self, commit=True):
    user = super().save(commit=False)
    user.set_password(self.cleaned_data["password1"])
    if commit:
        user.save()
        self.save_m2m()  # added this call to work as expected with models with `ManyToManyField`s
    return user
Last edited 6 years ago by Lemuel Formacil (previous) (diff)

comment:7 by Lemuel Formacil, 6 years ago

Cc: Lemuel Formacil added

comment:8 by Ülgen Sarıkavak, 9 months ago

Cc: Ülgen Sarıkavak added

comment:9 by Sarah Boyce, 7 months ago

#35484 is a duplicate, this generally tracks the work to make the UserAdmin work for custom user models 👍

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