Opened 22 months ago

Last modified 6 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: master
Severity: Normal Keywords: user, custom user, auth
Cc: Lemuel Formacil 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 22 months ago.
patch

Download all attachments as: .zip

Change History (8)

Changed 22 months ago by Rômulo Collopy

Attachment: patch.diff added

patch

comment:1 Changed 22 months ago by Tim Graham

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 Changed 22 months ago by Tim Graham

Triage Stage: UnreviewedAccepted

comment:3 Changed 20 months ago by shangdahao

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 Changed 19 months ago by Tim Graham <timograham@…>

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 Changed 10 months ago by Tim Graham

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 Changed 6 months ago by Lemuel Formacil

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 months ago by Lemuel Formacil (previous) (diff)

comment:7 Changed 6 months ago by Lemuel Formacil

Cc: Lemuel Formacil added
Note: See TracTickets for help on using tickets.
Back to Top