16👍
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())
def test_user_force_login(self):
# for testing, we can use force_login(),
# even if the user is created without arguments
user_without_args = User.objects.create()
self.client.force_login(user=user_without_args)
self.assertTrue(user_without_args.is_authenticated)
13👍
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.
- How do you get Django to make a RESTful call?
- AWS Elastic Beanstalk Container Commands Failing
- How to customize django rest auth password reset email content/template