【问题标题】:Setting password for user model in the admin page在管理页面中为用户模型设置密码
【发布时间】:2021-09-06 12:43:52
【问题描述】:

我创建了一个自定义 User 模型,其中包含多个角色客户和员工,其中员工也担任不同的角色:司机和管理人员。

我扩展了AbstractBaseUser模型类来设置一个自定义的用户模型:

class UserAccountManager(BaseUserManager):
    def create_superuser(self, email, first_name, last_name, password, **other_fields):

        other_fields.setdefault("is_staff", True)
        other_fields.setdefault("is_superuser", True)
        other_fields.setdefault("is_active", True)
        other_fields.setdefault("is_driver", True)
        other_fields.setdefault("is_customer", True)
        other_fields.setdefault("is_responsable", True)

        if other_fields.get("is_staff") is not True:
            raise ValueError(_("Superuser must be assigned to is_staff."))
        if other_fields.get("is_superuser") is not True:
            raise ValueError(_("Superuser must be assigned to is_superuser."))

        return self.create_user(email, first_name, last_name, password, **other_fields)

    def create_user(self, email, first_name, last_name, password, **other_fields):

        if not email:
            raise ValueError(_("You must provide an email address"))

        email = self.normalize_email(email)
        user = self.model(email=email, first_name=first_name, last_name=last_name, **other_fields)
        user.set_password(password)
        user.save()
        return user


class User(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(_("Email Address"), unique=True)
    first_name = models.CharField(_("First Name"), max_length=150, unique=True)
    last_name = models.CharField(_("Last Name"), max_length=150, unique=True)
    mobile = models.CharField(_("Mobile Number"), max_length=150, blank=True)
    is_active = models.BooleanField(_("Is Active"), default=False)
    is_staff = models.BooleanField(_("Is Staff"), default=False)
    is_driver = models.BooleanField(_("Is Driver"), default=False)
    is_responsable = models.BooleanField(_("Is Responsable"), default=False)
    is_customer = models.BooleanField(_("Is Customer"), default=False)
    created_at = models.DateTimeField(_("Created at"), auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(_("Updated at"), auto_now=True)

    objects = UserAccountManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["first_name", "last_name"]

    class Meta:
        verbose_name = "Account"
        verbose_name_plural = "Accounts"

    def __str__(self):
        return self.first_name

我创建了两种类型的模型来扩展此模型,它们分别代表不同的角色并继承自 User 模型:

class Employee(User):
    registration_number = models.PositiveSmallIntegerField(_("Driver Registration Number"), unique=True)
    picture = models.ImageField(
        verbose_name=_("Driver Pic"), help_text=_("Driver Identity Picture"), upload_to="images/driver/"
    )
    birth_date = models.DateField(_("Date Birth of the Driver"))
    city_id = models.ForeignKey("City", blank=True, null=True, on_delete=models.SET_NULL)
    bank_id = models.ForeignKey("Bank", blank=True, null=True, on_delete=models.SET_NULL)

    class Meta:
        verbose_name = "Employee"
        verbose_name_plural = "Employees"

    def __str__(self):
        return self.first_name + " " + self.last_name


class Customer(User):

    company_name = models.CharField(_("Company Name"), max_length=150, unique=True)
    website = models.CharField(_("Company website"), max_length=150, unique=True)
    mobile_2 = models.CharField(_("Mobile Number"), max_length=150, blank=True)
    
    class Meta:
        verbose_name = "Customer"
        verbose_name_plural = "Customers"

    def __str__(self):
        return self.first_name + " " + self.last_name

我想在admin.py中注册模型:

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
    pass


admin.site.register(Customer)
admin.site.register(Employee)

问题是,当我尝试从管理页面添加用户时,我无法为该用户设置密码,当我想在任何模型中添加新用户时出现密码字段,但该字段似乎与任何普通的 InputText 一样,点击时密码可见,并且在数据库中未注册密码。 我想在 model.py 中添加两种类型的 Employee :

class Responsable(Employee):
    responsability_type = models.CharField(max_length=4, blank=True)

    class Meta:
        verbose_name = "Responsable"
        verbose_name_plural = "Responsables"

    def __str__(self):
        return self.first_name + " " + self.last_name


class Driver(Employee):
    driving_licence = models.ImageField(
        verbose_name=_("Driver Licence"), help_text=_("Driver Licence Picture"), upload_to="images/driver_licence/"
    )
    driver_licence_expiration_date = models.DateField(_("Expiration Date for Driver Licence"))

    class Meta:
        verbose_name = "Driver"
        verbose_name_plural = "Drivers"

    def __str__(self):
        return self.first_name + " " + self.last_name

我不知道为这种角色设计这个模型是否是个好主意,我想避免得到多个表,其中存储了密码。

【问题讨论】:

    标签: django django-models django-views


    【解决方案1】:

    不要使用这样的模型继承,尤其是对于自定义 User 模型。创建一个继承自 AbstractBaseUser 的唯一模型,其中包含用户的类型以及您在当前表中声明的所有字段:

    class User(AbstractBaseUser, PermissionsMixin):
        class UserTypes(Enum):
            customer = ('cu', 'Customer')
            responsable = ('re', 'Responsable')
            driver = ('dr', 'Driver')
    
            @classmethod
            def get_value(cls, member):
                return cls[member].value[0]
    
        user_type = models.CharField(max_length=2, choices=[x.value for x in UserTypes])
        # Insert fields that are in common between all user types, for example:
        email = models.EmailField(_("Email Address"), unique=True)
        # Insert fields that could be None depending on the user type, for example:
        company_name = models.CharField(_("Company Name"), max_length=150, unique=True, null=True, blank=True)
    

    然后将其添加到您的设置中:

    AUTH_USER_MODEL = 'yourappname.User'
    

    您用于管理用户的ModelAdmin 应继承自UserAdmin 以允许密码管理:

    @admin.register(User)
    class UserAdmin(UserAdmin):
        fieldsets = ((None, {'fields': ('email', 'password', 'user_type', 'company_name')})) # Other fields showed when updating an user
        add_fieldsets = ((None, {'fields': ('email', 'password', 'user_type', 'company_name')})) # Other fields showed when creating an user
    

    【讨论】:

    • 我认为这会让我的观点更复杂,以应对不同的角色,但我会尝试这个建议。我不知道你为什么添加方法类`get_value()。
    • 我添加了方法类get_value,所以你可以写例如:User.objects.filter(user_type=User.UserTypes.get_value('driver'))。使用独特的模型,您的视图会更简单,只需要特定的用户类型并检查它以进行验证(类似于我在此评论中编写的代码)。对于多个模型,身份验证会更加困难。
    猜你喜欢
    • 2016-11-20
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多