【问题标题】:Django Admin Change password link brokenDjango 管理员更改密码链接已损坏
【发布时间】:2020-01-01 10:07:16
【问题描述】:

用户“Bob”的示例 Django 管理员:Home › Authentication and Authorization › Users › Bob

在 Django Admin 界面中修改用户时,在密码下显示:

未存储原始密码,因此无法查看此用户的密码,但您可以使用此表单更改密码。

但是,this form 链接失败并显示 Page not found 404,地址为:
http://127.0.0.1:8000/password/
而正确的 URL(有效)应该是:
http://127.0.0.1:8000/admin/auth/user/40/password/

经过一番搜索,我发现:Lib/site-packages/django/contrib/auth/forms.py:129

class UserChangeForm(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=\"{}\">this form</a>."
        ),
    )

但我没有看到更改密码链接是如何在 href 中设置的,对我来说它看起来是空白的。我也不想更改 Django 源代码,因为当有更新时会出现相同的错误。如何让链接指向有效的更改密码页面?

【问题讨论】:

    标签: python django django-admin


    【解决方案1】:

    您使用的是自定义用户模型还是用户管理员?如果是这种情况,您的管理类应该是 BaseUserAdmin 或继承自它。

    【讨论】:

      【解决方案2】:

      你没有使用这个UserChangeForm。对于自定义用户管理员,请遵循此文档Customizing Authentication

      【讨论】:

        【解决方案3】:

        原来是一个非常模糊的东西。因此,经过大量还原和修改新配置文件以使用旧代码后,设法将其缩小到我的一行:templates\admin\base.html&lt;head&gt; 部分的第一行是:

        <base href="/"><!-- For CSP stylesheet href links to pass MIME TYPE checks -->
        

        &lt;base&gt; 标签:

        为页面上的所有链接指定默认 URL 和默认目标

        【讨论】:

          【解决方案4】:

          href中的链接好像是在UserChangeForm__init__方法中设置的:

          def __init__(self, *args, **kwargs):
              super().__init__(*args, **kwargs)
              password = self.fields.get('password')
              if password:
                  password.help_text = password.help_text.format('../password/') # <-- here
              # ...
          
          

          我不知道你为什么要一直带你回到localhost:8000/password/,因为它是要上一个“目录”(从/admin/auth/user/40/change/admin/auth/user/40),然后再下到/admin/auth/user/40/password/

          这种href 格式的另一个含义是,如果您的URL 结构没有尾部斜杠(例如/.../users/40/change),则../password/ a。将带您到/.../users/password/,您将收到“没有 PK=password 的用户”错误,然后 b。无论如何都无法使用您的 URL 结构,因为它添加了一个斜杠。

          Django 没有办法覆盖它似乎很奇怪(例如通过传递UserChangeFormpassword_url 或其他东西)。这里可能有错误报告/功能建议...

          至于实际处理它,如this answer 中所建议的,一种选择是操纵您的 URL 配置以手动设置密码更改 URL 并将其指向相关的 admin / auth 视图。

          不幸的是,如果您在其他地方子类化或使用表单,这将无济于事。在这种情况下,到目前为止我想到的唯一解决方案是在您的子类的 __init__ 中手动替换它,如下所示:

          from django.contrib.auth import forms as auth_forms
          
          class UserEditForm(auth_forms.UserChangeForm):    
              def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)
                  password = self.fields.get('password')
                  if password:
                      password.help_text = password.help_text.replace(
                          '../password/', kwargs.pop('password_url', './password'))
          

          不幸的是,您必须使用.replace,因为一旦super().__init__ 格式化了帮助文本,您就无法重新格式化它,并且在调用super().__init__ 之前您不能这样做,因为您将无法访问场。此方法至少允许将 password_url 作为参数传递给表单,否则默认为 ./password,这将适用于没有尾部斜杠的 URL 结构。

          【讨论】: