[英]Django admin UserChangeForm with UUID field as primary key
I'm working on a Django app that will contain sensitive User data, so I'm taking a number of steps to anonymise User objects and their data. 我正在开发一个包含敏感用户数据的Django应用,因此我采取了许多步骤来匿名化用户对象及其数据。
I created custom 'User' object that subclassses the AbstractBaseUser model like so: 我创建了自定义“用户”对象,该对象将AbstractBaseUser模型子类化,如下所示:
class User(AbstractBaseUser, PermissionsMixin):
(...)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
(...)
It has the following linked ModelAdmin
object: 它具有以下链接的
ModelAdmin
对象:
from django.contrib.auth.forms import UserChangeForm
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
form = UserChangeForm
I'm using UUID fields for primary keys to ensure maximum anonymity, yet I would like to be able to reset User passwords in the Django Admin (like you can do with the default User
object) 我将UUID字段用作主键以确保最大程度的匿名性,但我希望能够在Django Admin中重置用户密码(就像您可以对默认
User
对象进行的操作一样)
However, when I open a User in the admin and press the link to change the password I get the following error message: 但是,当我以管理员身份打开用户并按链接更改密码时,出现以下错误消息:
User with ID "21362aca-6918-47ea-9b29-275350a89c54/password" doesn't exist. Perhaps it was deleted?
The admin url is still expecting a url with the an integer as its pk
value. 管理员url仍期望以整数作为
pk
值的url。
So it seems that I have to override the admin url configuration in the ModelAdmin definition, but I was wondering if there was a simpler way to achieve the desired result - as I imagine that replacing the User.pk with an UUID field is a fairly regular occurrence and I image many developers have ran into this problem. 因此,似乎必须重写ModelAdmin定义中的admin url配置,但是我想知道是否有一种更简单的方法来实现所需的结果-因为我想用UUID字段替换User.pk是相当正常的发生和我的形象许多开发人员都遇到了这个问题。 I tried to find some kind of settings / toggle to achieve this but to no avail, am I missing something?
我试图找到某种设置/切换来实现此目的,但无济于事,我是否缺少某些东西?
Your 'UserAdmin' inherits from ModelAdmin
, which provides the urls via the get_urls
method for the add, change, delete, etc. views but also a 'fallback' url: 您的“ UserAdmin”继承自
ModelAdmin
,后者通过get_urls
方法提供了用于添加,更改,删除等视图的URL,还提供了一个“后备” URL:
urlpatterns = [
#...
url(r'^(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info),
# For backwards compatibility (was the change url before 1.9)
path('<path:object_id>/', wrap(RedirectView.as_view(
pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
))),
]
The url you are following looks like /user/<UUID>/password/
which only fits the regex of the fallback pattern - which redirects you to the change page in such a way that it uses <UUID>/password
as the object_id
. 您要跟踪的url类似于
/user/<UUID>/password/
,它仅适合后备模式的正则表达式-它将您重定向到更改页面,使其使用<UUID>/password
作为object_id
。
Try inheriting from django.contrib.auth.admin.UserAdmin
instead as its get_urls
method provides the url pattern you need. 尝试从
django.contrib.auth.admin.UserAdmin
继承,因为其get_urls
方法提供了所需的url模式。
Some more poking around... 还有一些戳...
If your primary key field was an AutoField, the whole process would raise a ValueError('invalid literal for int')
when trying to cast int('some_integer/password')
in django.db.models.fields.AutoField.get_prep_value
in order to prepare the value for a query. 如果您的主键字段是一个AutoField,则整个过程将在尝试按顺序在
django.db.models.fields.AutoField.get_prep_value
中int('some_integer/password')
时引发ValueError('invalid literal for int')
int('some_integer/password')
。为查询准备值。 Understandable! 可以理解的!
HOWEVER : UUIDField
uses the get_prep_value
method of the base class Field
. 但是,
UUIDField
使用基类Field
的get_prep_value
方法。 Field.get_prep_value
just simply returns the value without even checking (after all, validating the value should be the job of UUIDField
). Field.get_prep_value
只是简单地返回值,甚至不进行检查(毕竟,验证值应该是UUIDField
的工作)。 So you end up with a query that looks for the bogus uuid '<uuid>/password'
, which obviously doesn't exist. 因此,您最终得到一个查询,该查询将查找虚假的uuid
'<uuid>/password'
,这显然不存在。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.