Reputation: 37
So, I am working my way through the jungle of the django documentation in order to create an online classifieds app. Since users are supposed to be anble to post their own classifieds online, I need to make use of the user authentication system. However, they need to be able to log in by email instead of username, which is why I need to come up with a customized user model.
Now, the example walk-through thats contained in the django documentation seems helpful:
https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#a-full-example
In order to understand django better, I am trying to go through the example line by line, and there is a point that I don't quite get:
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
I don't get where the "self.model(...)" comes from. Is it a method? I cannot find it in BaseUserManager... where is it defined? I don't even quite know how to phrase the question precisely because I'm so puzzled about it... could anybody just enlighten me about what we are defining here and for what purpose? And from which django model does it originally come from?
Thanks for your support in advance!
Upvotes: 2
Views: 92
Reputation: 1388
U can replace any field with username. for example mobile_number.
User Manager:
class MyUserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, mobile_number, password, **extra_fields):
if not mobile_number:
raise ValueError('The given username must be set')
# email = self.normalize_email(email)
mobile_number = self.normalize_mobile_number(mobile_number)
user = self.model(mobile_number=mobile_number, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, mobile_number, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(mobile_number, password, **extra_fields)
def create_superuser(self, mobile_number, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(mobile_number, password, **extra_fields)
def normalize_mobile_number(self, mobile_number):
return mobile_number
User Model:
class User(AbstractUser):
mobile_number = models.CharField(max_length=50,
unique=True,
verbose_name=_('Mobile Number'),
error_messages={
'unique': _("A user with that mobile number already exists."),
},
)
USERNAME_FIELD = 'mobile_number'
REQUIRED_FIELDS = []
objects = MyUserManager()
Upvotes: 0
Reputation: 8506
It's part of the declaration of BaseManager:
#django.db.models.manager.BaseManager
def __init__(self):
super().__init__()
self._set_creation_counter()
self.model = None
self.name = None
self._db = None
self._hints = {}
Upvotes: 1
Reputation: 477170
A Django model takes a ModelBase
as metaclass. Indeed, we see in the source code [GItHub]:
class Model(metaclass=ModelBase): # …
Now when you thus construct a model class (not an object), it will run the __new__
method of the metaclass. This method will check if the items in the class have a .contribute_to_class(..)
method, as we can see in a (shorted) version of the __new__
method [GitHub] here:
def __new__(cls, name, bases, attrs, **kwargs): # … for obj_name, obj in list(attrs.items()): if _has_contribute_to_class(obj): contributable_attrs[obj_name] = obj else: new_attrs[obj_name] = obj # … for obj_name, obj in contributable_attrs.items(): new_class.add_to_class(obj_name, obj) # … return new_class
It will thus call the add_to_class
with the name of the object, and the object (the field) on the method class.
This method is implemented as [GitHub]:
def add_to_class(cls, name, value): if _has_contribute_to_class(value): value.contribute_to_class(cls, name) else: setattr(cls, name, value)
It will thus set the attribute to the class, and call the contribute_to_class
on that object, with the model class as first parameter, and the name as second parameter.
If that object is a Manager
object, the contribute_to_class
method is implemented as [GitHub]:
def contribute_to_class(self, model, name): self.name = self.name or name self.model = model setattr(model, name, ManagerDescriptor(self)) model._meta.add_manager(self)
so it will set the model
attribute of the manager to the class where you added the manager to. In case you thus add this to the User
model, then self.model
will refer to the User
class. If you then call self.model(email='[email protected]', date_of_birth='1-1-2019')
, then it will thus construct a User
model object with '[email protected]'
as email
, and 1-1-2019
as date_of_birth
.
Upvotes: 3