User manager methods create() and create_user()
-
21-06-2021 - |
Question
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?
Solution
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:
If you run the management command
python manage.py sql
, pay attention to theauth_user
schema:CREATE TABLE "auth_user" ( ... "password" varchar(128) NOT NULL, ... )
In SQL, an empty string,
''
, does not equate toNULL
, i.e.ISNULL('') != TRUE
.QuerySet.create()
andQuerySet.update()
do not trigger model validation. Model validation only happens whenModelForm
instances call theModel.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 likeUser.objects.create(username='foo', password='')
even thoughCharField().validate(value='', None)
would raise aValidationError
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.
OTHER TIPS
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