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