However, for simple subclasses of `AbstractUser` it's actually simpler to
extend (rather than rewrite) the existing form like so:
{{{
#!python
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
}}}
Unfortunately, this fails because the `clean_username` method of
`UserCreationForm` still references the original `User` model directly
(this technique works with `UserChangeForm` though).
To get it working, the original `clean_username` method needs to be copied
over and modified to use the custom user model, like so:
{{{
#!python
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
def clean_username(self):
username = self.cleaned_data["username"]
try:
CustomUser.objects.get(username=username)
except CustomUser.DoesNotExist:
return username
raise
forms.ValidationError(self.error_messages['duplicate_username'])
}}}
This works, but having to copy/paste some code is not a very good
practice.
Therefore, I propose to change `UserCreationForm.clean_username` to use
`Meta.model` instead of `User`.
This allows the creation of custom user creation forms by simply
redefining the user model in the form's `Meta` class (like in the first
example).
The documentation could also be extended to show an example of how to
extend the builtin auth forms that require it.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_better_patch: => 0
* has_patch: 0 => 1
* needs_tests: => 0
* needs_docs: => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:1>
* needs_tests: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:2>
* needs_tests: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:3>
* needs_docs: 0 => 1
* stage: Unreviewed => Accepted
Comment:
Seems like a reasonable idea to me. Patch needs a documentation update to
point out the changed constraints on form usage.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:4>
Comment (by bmispelon):
I've updated the patch with some documentation.
I've also started a branch on my fork:
https://github.com/bmispelon/django/tree/ticket-19353
The wording on the documentation feels a bit awkward and I'd appreciate
comments and ideas to improve it.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:5>
* cc: aenor.realm@… (added)
Comment:
On a related note, i've added some fields to my subclass of AbstractUser
and admin fieldset setting now complains about missing fields from the
[change] form. The fix is to use get_user_model() in Meta too.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:6>
Comment (by rpedigoni):
Replying to [comment:5 bmispelon]:
> I've updated the patch with some documentation.
>
> I've also started a branch on my fork:
https://github.com/bmispelon/django/tree/ticket-19353
>
> The wording on the documentation feels a bit awkward and I'd appreciate
comments and ideas to improve it.
I just made a similar fix and right before sending a pull request I found
your ticket :)
Could submit a pull request?
Also, I left a comment on your branch about the username field:
https://github.com/bmispelon/django/commit/81c9bd6a2a55a8cf1c2bee351db873ea7403db1e#commitcomment-2507426
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:7>
* cc: mjumbewu (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:8>
* cc: victorhooi@… (added)
Comment:
Hi,
Curious - what is the status on this ticket?
Are there still blockers on it being accepted?
Cheers,
Victor
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:9>
Comment (by dominicrodger):
I ran into this problem today, and was very confused (the stack trace you
get when this goes wrong doesn't lead you quickly to where the problem
occurred). The patch looks reasonable to me - it's got tests, docs, and a
simple enough implementation. Is there anything we can do to get it
committed? I'm more than happy to do any additional work here if it'd
help, if Baptiste doesn't have time to work on it at the moment.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:10>
* cc: internet@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:11>
* cc: flisky (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:12>
* cc: maestrofjp (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:13>
Comment (by timo):
This should be easier after removing some of the logic from the form in
#13147.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:14>
Comment (by Loic Bistuer <loic.bistuer@…>):
In [changeset:"671e0c937c112b1908048b4d8deb14c0116b8946"]:
{{{
#!CommitTicketReference repository=""
revision="671e0c937c112b1908048b4d8deb14c0116b8946"
Further fix the release notes for refs #13147.
Mention of custom user models has been removed since UserCreationForm
didn't support custom user models anyway. Refs #19353.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:15>
Comment (by berkerpeksag):
Since 849538d03df21b69f0754a38ee4ec5f48fa02c52 has been committed, I think
`UserCreationForm` works well with subclasses of `AbstractUser`. Here is a
test case:
{{{
diff --git a/tests/auth_tests/test_forms.py
b/tests/auth_tests/test_forms.py
index aa0a6af..68a1b88 100644
--- a/tests/auth_tests/test_forms.py
+++ b/tests/auth_tests/test_forms.py
@@ -10,6 +10,7 @@ from django.contrib.auth.forms import (
SetPasswordForm, UserChangeForm, UserCreationForm,
)
from django.contrib.auth.models import User
+from django.contrib.auth.tests.custom_user import ExtensionUser
from django.contrib.sites.models import Site
from django.core import mail
from django.core.mail import EmailMultiAlternatives
@@ -153,6 +154,20 @@ class UserCreationFormTest(TestDataMixin, TestCase):
form['password2'].errors
)
+ def test_custom_form(self):
+ class CustomUserCreationForm(UserCreationForm):
+ class Meta(UserCreationForm.Meta):
+ model = ExtensionUser
+ fields = UserCreationForm.Meta.fields +
('date_of_birth',)
+
+ data = {
+ 'username': 'testclient',
+ 'password1': 'testclient',
+ 'password2': 'testclient',
+ 'date_of_birth': '1988-02-24',
+ }
+ form = CustomUserCreationForm(data)
+ self.assertTrue(form.is_valid())
@override_settings(USE_TZ=False,
PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'])
class AuthenticationFormTest(TestDataMixin, TestCase):
}}}
I can send this as a PR, if it looks reasonable.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:16>
* cc: berker.peksag@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:17>
Comment (by timgraham):
Sure, might want to also consider including some documentation updates
from bmispelon's branch in comment 5.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:18>
Comment (by bmispelon):
I'm also curious to see if `UserChangeForm` can now also be used.
FYI, the documentation moved to
https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-
users-and-the-built-in-auth-forms since the original ticket was opened.
Thanks.
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:19>
* owner: nobody => berkerpeksag
* needs_docs: 1 => 0
* status: new => assigned
Comment:
Pull request: https://github.com/django/django/pull/6142
* Converted my test in comment 16 to an actual test case
* Added a test for UserChangeForm
* Ported documentation updates from bmispelon's branch in comment 5
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:20>
Comment (by Tim Graham <timograham@…>):
In [changeset:"f0425c72601f466c6a71518749c6d15b94945514" f0425c7]:
{{{
#!CommitTicketReference repository=""
revision="f0425c72601f466c6a71518749c6d15b94945514"
Refs #19353 -- Added tests for using custom user models with built-in auth
forms.
Also updated topics/auth/customizing.txt to reflect that subclasses of
UserCreationForm and UserChangeForm can be used with custom user models.
Thanks Baptiste Mispelon for the initial documentation.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:21>
Comment (by Tim Graham <timograham@…>):
In [changeset:"f78892f2de1e986f00d23581dc006e90e26abd8f" f78892f2]:
{{{
#!CommitTicketReference repository=""
revision="f78892f2de1e986f00d23581dc006e90e26abd8f"
[1.9.x] Refs #19353 -- Added tests for using custom user models with
built-in auth forms.
Also updated topics/auth/customizing.txt to reflect that subclasses of
UserCreationForm and UserChangeForm can be used with custom user models.
Thanks Baptiste Mispelon for the initial documentation.
Backport of f0425c72601f466c6a71518749c6d15b94945514 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:22>
* status: assigned => closed
* resolution: => fixed
Comment:
If there are any further improvements, let's open a new ticket. Thanks!
--
Ticket URL: <https://code.djangoproject.com/ticket/19353#comment:23>