【问题标题】:Django customized user model.... where does user.model(...) come from?Django 自定义用户模型.... user.model(...) 来自哪里?
【发布时间】:2019-11-22 15:13:29
【问题描述】:

所以,我在 django 文档的丛林中工作,以创建一个在线分类应用程序。 由于用户应该能够在线发布他们自己的分类,我需要使用用户身份验证系统。但是,他们需要能够通过电子邮件而不是用户名登录,这就是为什么我需要提出一个定制的用户模型。

现在,django 文档中包含的示例演练似乎很有帮助:

https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#a-full-example

为了更好地理解django,我试着逐行浏览示例,有一点我不太明白:

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,
    )

我不明白“self.model(...)”的来源。它是一种方法吗?我在 BaseUserManager 中找不到它......它在哪里定义?我什至不知道如何准确地表达这个问题,因为我对此感到非常困惑......有人可以告诉我我们在这里定义什么以及出于什么目的?它最初来自哪个 django 模型?

提前感谢您的支持!

【问题讨论】:

  • 当您将Manager 对象添加到您的类时,它将在管理器对象中添加对模型对象的引用。这是通过元类逻辑完成的。
  • @WillemVanOnsem 我建议将其发布为答案。解释那里发生的一些魔法。

标签: python django


【解决方案1】:

Django 模型将ModelBase 作为元类。确实,我们在source code [GItHub]看到:

class Model(metaclass=ModelBase):
    # …

现在,当您构造一个模型(不是对象)时,它将运行元类的__new__ 方法。该方法将检查类中的项目是否具有.contribute_to_class(..) 方法,正如我们在(shorted) version of the __new__ method [GitHub] 中看到的那样:

    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

因此它将使用对象名称和方法类上的对象(字段)调用add_to_class

这个方法是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)

它会将属性设置为类,并在该对象上调用contribute_to_class,模型class作为第一个参数,名称作为第二个参数。

如果该对象是Manager 对象,则contribute_to_class 方法是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)

因此它会将经理的model 属性设置为您将经理添加到的类。如果您因此将其添加到 User 模型中,则 self.model 将引用 User 类。如果你随后调用self.model(email='foo@bar.com', date_of_birth='1-1-2019'),那么它将因此构造一个User 模型对象,其中'foo@bar.com'email1-1-2019date_of_birth

【讨论】:

  • 哇,解释的辛苦了! ...因此... =D,我会感谢你的!不过,我需要经过 2 到 3 次才能完全融入其中。但这绝对有帮助!
【解决方案2】:

这是 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 = {}

【讨论】:

    【解决方案3】:

    U 可以用用户名替换任何字段。例如 mobile_number。

    用户管理器:

    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
    

    用户模型:

    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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-23
      • 2014-01-04
      • 2012-06-28
      • 2012-05-05
      • 2014-02-07
      • 2015-03-08
      相关资源
      最近更新 更多