【发布时间】:2021-09-07 10:00:07
【问题描述】:
我们正在尝试构建端点以允许用户从我们的前端编辑他们自己的配置文件,我们在尝试编辑“登录用户”时遇到了问题。这个问题也发生在 django admin 中。
这篇文章的其余部分都是专门指 django admin 中的“用户”。我已经扩展了用户并建立了一个自定义管理员。
如果我们有 3 个用户,(现在假设这三个用户都是超级用户/is_staff)。登录用户 1,我可以编辑用户 2 和 3,但是当我去编辑用户 1(登录用户)时,消息说它已更新但数据库没有更改。
如果我以用户 2 身份登录并更新用户 1,我可以将用户 1 更新为登录用户,但不能更新用户 2。
同样的行为也发生在我们的 request.user 端点上。 request.user 可以编辑除登录用户之外的任何用户。
代码
accounts/models.py
class User(AbstractUser):
timezone = models.CharField(max_length=255, blank=True, null=True)
is_customer = models.BooleanField(default=False)
is_agent = models.BooleanField(default=False)
is_carrier = models.BooleanField(default=False)
is_shipper = models.BooleanField(default=False)
is_tracking = models.BooleanField(default=False)
class Meta:
db_table = 'auth_user'
def __str__(self):
return self.first_name
在设置中定义:
AUTH_USER_MODEL = 'accounts.User'
accounts/admin.py
CustomUser = get_user_model()
class UserInline(admin.StackedInline):
model = User
class AgentInline(admin.StackedInline):
model = Agent
class CustomUserAdmin(UserAdmin):
model = CustomUser
agent_fields = ('timezone', 'is_agent', 'is_customer', 'is_shipper', 'is_carrier', 'is_tracking')
fieldsets = UserAdmin.fieldsets + (
('Agent Info', {'fields': agent_fields}),
)
inlines = [
AgentInline,
]
admin.site.register(CustomUser, CustomUserAdmin)
迁移 0001_initial.py
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('is_customer', models.BooleanField(default=False)),
('is_agent', models.BooleanField(default=False)),
('is_carrier', models.BooleanField(default=False)),
('is_shipper', models.BooleanField(default=False)),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]
我的测试截图
这是 UPDATE 的输出,您可以看到名字被保存为空白字符串。所以也许这与形式有关?
当我们添加自定义用户模型时,我们可能做错了什么,因为我认为它是在项目创建之后添加的。
因此,我假设登录的用户可能正在更改数据库中的错误表。不过,我不确定如何识别它,通常我会使用 shell,但由于我们的自定义模型,原始 auth_user 模型被禁止导入。
如果我可以提供更多上下文,请告诉我。
更新 1
看起来更新确实有效,然后它会立即被原始数据覆盖。请参阅此屏幕截图,这发生在一次更新中。您可以看到一个 UPDATE 语句,其中姓氏有一个值,然后是第二个带有原始数据的 UPDATE。
【问题讨论】:
-
minimal reproducible example 肯定会有所帮助。 You can make django log all executed sql queries (example),这可能会提示您正确的方向。只是为了确保:更新后,
request.user没有更新,你必须打电话给refresh_from_db才能看到那里的更新——我猜你是这样做的? -
可以添加用户编辑相关的代码吗?如果代码使用了错误的表,我认为不应该这样做,那么登录用户也不应该能够更新其他用户。另外,当您说您收到用户已更新的消息时,您是在打开用户编辑页面还是在单击保存后收到它?你如何确定用户没有真正更新?
-
我添加了更多代码来显示我所指的 admin.py,并添加了一些屏幕截图来向您展示我是如何测试它的。
-
@He3lixxx,我能够打印出 SQL,但有些东西很时髦,因为我正在尝试更新名字,但 SQL 传递的是空白字符串而不是我的值。
-
添加了更新,sql 显示更新,然后显示原始数据的重复更新。添加了要显示的屏幕截图。
标签: django