I'm creating new users using a custom UserCreationForm
and then using password_reset
from auth.views
with a customized email template to send a signup mail to the user.
This process is working fine, users are able to successfully complete the signup process and start using the app. I now want to create users without having to set a password for the user.
I tried setting self.fields['password1'].required
and self.fields['password2'].required
to False
in the UserCreationForm
init method as recommended here but that hasn't worked for me. Unfortunately, it's proving difficult to debug. I'm not seeing any error messages but I know the RegistrationView
register method isn't getting called.
Here's my UserCreationForm
class UserCreateForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("email",)
def __int__(self):
self.fields['password1'].required = False
self.fields['password2'].required = False
def save(self, commit=True):
user = super(UserCreateForm, self).save(commit=False)
clean_email = self.cleaned_data["email"]
user.email = clean_email
if commit:
user.save()
custom_user = CustomUser()
custom_user.id = user
custom_user.save()
return user
Here's my RegistrationView
class UserRegistration(RegistrationView):
def __init__(self):
self.form_class = UserCreateForm
self.success_url = 'login'
self.template_name = 'register.html'
def register(self, request, form):
new_user = form.save()
I'm using Django 1.8. Please let me know if any other information would be useful to share.
Programmatically, you can create
/save
a new User
without a password argument, and it will not raise any exceptions. In fact, you can even create
a user without any arguments. This is explained here.
The trick is to use create()
instead of create_user(), as discussed here.
For example, you can do this in your code:
User.objects.create(username='user without password')
The database field password
will then contain an empty string. Because the user now exists, the admin will show the UserChangeForm
, and the password will show up as a ReadOnlyPasswordHashField which says "No password set.", as you can see in the image below. You can proceed normally from there.
Note that this empty password is not the same as an unusable password. The PasswordResetView
does not work with an unusable password, but it does work with an empty password.
Also note that User.objects.create(password='')
works, but User.objects.create(password=None)
does not: the latter raises a IntegrityError
due to the NOT NULL
constraint in the database.
Just to illustrate the options, here's a test with different ways to create a user:
from django.test import TestCase
from django.contrib.auth.models import User
from django.contrib.auth.hashers import make_password
import django.db
import django.db.transaction
RAW_PASSWORD = 'mypassword'
class UserTests(TestCase):
def tearDown(self) -> None:
# print passwords as stored in test database
for user in User.objects.all():
print(f'username: {user.username}\tpassword: {user.password}')
def test_user_create_missing_required_fields(self):
# none of these raise any exceptions, despite required model fields
user_kwargs = [dict(),
dict(username='a'),
dict(username='b', password=''),
dict(username='c', password=RAW_PASSWORD)]
for kwargs in user_kwargs:
user = User.objects.create(**kwargs)
# password is "usable" ...
self.assertTrue(user.has_usable_password())
if 'password' in kwargs:
# stored password is still raw (not hashed)
self.assertEqual(kwargs['password'], user.password)
# ... but password-check fails
self.assertFalse(user.check_password(kwargs['password']))
def test_user_set_password(self):
# can set a usable password after user creation
user = User(username='d')
user.set_password(RAW_PASSWORD) # does not save...
user.save()
self.assertTrue(user.has_usable_password())
self.assertNotEqual(RAW_PASSWORD, user.password)
self.assertTrue(user.check_password(RAW_PASSWORD))
def test_user_create_hashed_password(self):
# we can initialize with a hashed password
hashed_password = make_password(RAW_PASSWORD)
user = User.objects.create(username='e', password=hashed_password)
self.assertTrue(user.has_usable_password())
self.assertTrue(user.check_password(RAW_PASSWORD))
def test_user_set_unusable_password(self):
# can set an unusable password
user = User(username='f')
user.set_unusable_password() # does not save...
user.save()
self.assertFalse(user.has_usable_password())
@django.db.transaction.atomic
def test_user_create_password_none(self):
# cannot initialize with password=None (violates the NOT NULL constraint)
with self.assertRaises(django.db.IntegrityError) as a:
User.objects.create(username='g', password=None)
self.assertIn('not null', str(a.exception).lower())
def test_user_set_password_none(self):
# can set None in set_password(), but that becomes unusable
user = User(username='h')
user.set_password(None)
user.save()
self.assertFalse(user.has_usable_password())
As you described, you modified the form fields to not require password, but what about the model? The build-in User
model enforces use of password (it is required model field), and will give errors if you try to save a User
objects without one. There's a special method for when you don't want to set a real password - django.contrib.auth.models.User.set_unusable_password()
. Use it in your view before saving the form data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With