英文:
In Django Admin site password field changes when I edit the attribute of other widgets
问题
在默认的Django管理站点中,"Password"字段显示加密方式,并提供更改密码的链接。
在我的项目中,我需要将一些字段设置为从左到右(LTR),因为该站点是从右到左(RTL)的。这是我所做的:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
from django import forms
from .models import CustomUser
# 在这里注册您的模型
class CustomUserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['email'].widget.attrs.update({'dir': 'ltr'})
self.fields['national_id'].widget.attrs.update({'dir': 'ltr'})
self.fields['mobile_number'].widget.attrs.update({'dir': 'ltr'})
@admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
form = CustomUserForm
# 其他配置选项...
但是使用这个自定义表单后,"Password"字段看起来是这样的:
我没有改动与此相关的任何内容。为什么会发生这种变化?
编辑:
如您所请求,这是自定义用户模型:
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractUser
from django.contrib.auth.hashers import make_password
from django.utils.translation import gettext_lazy as _
# 创建您的模型
class CustomUserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""
创建并保存具有给定电子邮件和密码的用户
"""
if not email:
raise ValueError('必须设置电子邮件')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.password = make_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password=None, **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('超级用户必须具备 is_staff=True。')
if extra_fields.get('is_superuser') is not True:
raise ValueError('超级用户必须具备 is_superuser=True。')
return self._create_user(email, password, **extra_fields)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('电子邮件地址'), unique=True)
is_verified = models.BooleanField(
_('已验证状态'),
blank=True,
default=False,
help_text=_('指示用户是否已验证其电子邮件地址。'),
)
national_id = models.CharField(
_('国民身份证'),
max_length=10,
unique=True,
blank=True,
null=True,
help_text=_('10位国民身份证号码'),
)
mobile_number = models.CharField(
'手机号码',
max_length=13,
unique=True,
blank=True,
null=True,
help_text='包括国家代码(+98)的13位手机号码',
)
home_address = models.TextField(
'家庭地址',
blank=True,
)
work_address = models.TextField(
'工作地址',
blank=True,
)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('用户')
verbose_name_plural = _('用户')
permissions = (('can_verify_user', _('可以验证用户')),)
无论是否使用自定义表单,其他所有内容都与Django的默认管理站点完全相同。只有"Password"字段发生了变化。
英文:
In the default Django Admin site, the Password
field shows how it is encrypted and there's a link to change it.
In my project I need to set some fields to LTR (because the site is in RTL), so this is what I do:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
from django import forms
from .models import CustomUser
# Register your models here.
class CustomUserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['email'].widget.attrs.update({'dir': 'ltr'})
self.fields['national_id'].widget.attrs.update({'dir': 'ltr'})
self.fields['mobile_number'].widget.attrs.update({'dir': 'ltr'})
@admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
form = CustomUserForm
fieldsets = (
(None, {'fields': ('email', 'password')}),
(
_('Personal info'),
{
'fields': (
'first_name',
'last_name',
)
},
),
(
_('Profile info'),
{
'fields': (
'national_id',
'mobile_number',
'home_address',
'work_address',
)
},
),
(
_('Permissions'),
{
'fields': (
'is_active',
'is_staff',
'is_superuser',
'is_verified',
'groups',
'user_permissions',
),
},
),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
(
None,
{
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
},
),
)
list_display = ('email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
search_fields = ('email', 'first_name', 'last_name', 'national_id', 'mobile_number')
ordering = ('email',)
filter_horizontal = (
'groups',
'user_permissions',
)
But with that custom form, the Password
field looks like this:
I have not touched anything related to it. Why it is changing?
EDIT:
As requested, here's the custom user model:
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractUser
from django.contrib.auth.hashers import make_password
from django.utils.translation import gettext_lazy as _
# Create your models here.
class CustomUserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""
Create and save a user with the given email and password
"""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.password = make_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password=None, **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(email, password, **extra_fields)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
is_verified = models.BooleanField(
_('verified status'),
blank=True,
default=False,
help_text=_('Designates whether this user has verified their email address.'),
)
national_id = models.CharField(
_('National ID'),
max_length=10,
unique=True,
blank=True,
null=True,
help_text=_('10-digit National ID number'),
)
mobile_number = models.CharField(
'Mobile Number',
max_length=13,
unique=True,
blank=True,
null=True,
help_text='13-digit mobile number including country code (+98)',
)
home_address = models.TextField(
'home address',
blank=True,
)
work_address = models.TextField(
'work address',
blank=True,
)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
permissions = (('can_verify_user', _('Can verify user')),)
With or without that custom form, everything else looks exactly the same as Django's default Admin site. It is only the Password
field that changes.
答案1
得分: 1
这是因为您正在使用CustomUserForm覆盖默认的User Admin表单。如果您想处理这种情况,您也必须在您的表单中处理密码字段,就像这样:
from django.contrib.auth.forms import ReadOnlyPasswordHashField
class CustomUserForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(
label="密码",
help_text=(
"原始密码不会被存储,因此无法查看此用户的密码,但您可以使用<a href=\"../password/\">此表单</a>更改密码。"
),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['email'].widget.attrs.update({'dir': 'ltr'})
self.fields['national_id'].widget.attrs.update({'dir': 'ltr'})
self.fields['mobile_number'].widget.attrs.update({'dir': 'ltr'})
class Meta:
model = CustomUser
fields = '__all__'
请注意,我已经将HTML实体(如"
和<
)翻译回了相应的字符。
英文:
It is because you are overriding default User Admin form with CustomUserForm. If you want to handle this situation you have to handle password field in your form too like this:
from django.contrib.auth.forms import ReadOnlyPasswordHashField
class CustomUserForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(
label=("Password"),
help_text=(
"Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using <a href=\"../password/\">this form</a>."
),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['email'].widget.attrs.update({'dir': 'ltr'})
self.fields['national_id'].widget.attrs.update({'dir': 'ltr'})
self.fields['mobile_number'].widget.attrs.update({'dir': 'ltr'})
class Meta:
model = CustomUser
fields = '__all__'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论