User manager methods create() and create_user()
Asked Answered
C

2

13

I have encountered with some suspicious behavior of create() method of User object manager. Looks like password field isn't required for creating User object if you use this method. In result you get User with blank password. In case when you use create_user method and don't specify password it creates User with unusable password (through to set_unusable_password()).

I am not sure why create() method doesn't raise exception when you try to create user without password - in documentation it's specified that this field is required. Is something wrong in create() method/documentation?

Cocks answered 18/7, 2012 at 15:2 Comment(0)
P
19

That's exactly why the user model has a custom manager with a UserManager.create_user() method for creating users. There are two problems with using the QuerySet.create() method on User instances:

  1. If you run the management command python manage.py sql, pay attention to the auth_user schema:

    CREATE TABLE "auth_user" (
        ...
        "password" varchar(128) NOT NULL,
        ...
    )
    

    In SQL, an empty string, '', does not equate to NULL, i.e. ISNULL('') != TRUE.

  2. QuerySet.create() and QuerySet.update() do not trigger model validation. Model validation only happens when ModelForm instances call the Model.full_clean() instance method.

    Raising a validation error in the context of working with the QuerySet API directly simply makes no sense in Django. That's why you can do something like User.objects.create(username='foo', password='') even though CharField().validate(value='', None) would raise a ValidationError for a blank string.

For the reasons above, you should defer from using User.objects.create() and rely on the supplied User.objects.create_user() method from the model's custom manager.

Pedal answered 18/7, 2012 at 15:43 Comment(1)
what if I don't use ModelForm and want to trigger model validation?Valgus
C
1

Look at django's source User model, there's a custom manager, snippet:

class UserManager(models.Manager):
    # ...   
    def create_user(self, username, email=None, password=None):
        """
        Creates and saves a User with the given username, email and password.
        """
        now = timezone.now()
        if not username:
            raise ValueError('The given username must be set')
        email = UserManager.normalize_email(email)
        user = self.model(username=username, email=email,
                          is_staff=False, is_active=True, is_superuser=False,
                          last_login=now, date_joined=now)

        user.set_password(password)
        user.save(using=self._db)
        return user
Chassidychassin answered 18/7, 2012 at 15:24 Comment(2)
I understand that password isn't required for create_user. It has been implemented if you authenticate against some external source. I just thinking that it's not appropriate behavior for User's manager create() method.Cocks
No, because User has a custom manager defined but uses the same variable 'objects' createChassidychassin

© 2022 - 2024 — McMap. All rights reserved.