【问题标题】:Django 1.5 custom User model error. "Manager isn't available; User has been swapped"Django 1.5 自定义用户模型错误。 “经理不可用;用户已被交换”
【发布时间】:2012-11-14 03:01:25
【问题描述】:

我按照开发文档中的描述扩展了 django 用户模型。我不想保留大部分原始用户模型功能,所以我扩展了 AbstractUser 类。我已经在 settings.py 中定义了:

AUTH_USER_MODEL = 'myapp.CustomUser'

我的用户类:

class CustomUser(AbstractUser):
  custom_field = models.ForeignKey('OtherModel')
  objects = UserManager()

一切似乎都很好,但是当我尝试让它由管理站点管理时:

admin.site.register(CustomUser, UserAdmin)

我在管理自定义用户创建页面上收到此错误(在验证密码确认表单后):

AttributeError: Manager isn't available; User has been swapped for 'myapp.CustomUser'

关键是我需要这个由管理站点管理的模型,以便拥有与原始用户模型相同的创建过程(密码验证的两步过程)。

【问题讨论】:

  • @thecore 的第一行正确修复了问题 (stackoverflow.com/a/13641427/11698)。也许您可以将其标记为“答案”——这样可以节省我的时间! ;)
  • @RichardCorden 谢谢!!!

标签: django django-admin django-users


【解决方案1】:

您只需要更改表单即可添加用户(覆盖 clean_username 并在 get_user_model() 上更改用户

完整的工作示例(如果您从 AbstractUser 继承)

from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm


class MyUserChangeForm(UserChangeForm):

    class Meta:
        model = get_user_model()

class MyUserCreationForm(UserCreationForm):

    class Meta:
        model = get_user_model()

    def clean_username(self):
        username = self.cleaned_data["username"]
        try:
            get_user_model().objects.get(username=username)
        except get_user_model().DoesNotExist:
            return username
        raise forms.ValidationError(self.error_messages['duplicate_username'])

class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm
    add_form = MyUserCreationForm
    fieldsets = (
        (None, {'fields': [('username', 'password'),]}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
                                   'groups', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        )

admin.site.register(MyUser, MyUserAdmin)

【讨论】:

  • 您可以将答案拆分为解决问题所需的最低要求(即使用 get_user_model 并覆盖 clean_username),以强调这就是所有需要的。更多信息可以在这里找到 (code.djangoproject.com/ticket/19353)
  • 我在查看此票之前写下答案。现在看看票没有关闭。
  • 好的 - 反正你得到了 +1!
  • :) 真正的不仅 get_user_model 是答案。需要为更改和创建用户重新定义表单,否则管理员会出错。我看到票证-可能不想丢失向后兼容并在表单 Meta 中添加 get_user_model() ..
【解决方案2】:

我为这个错误苦苦挣扎了好几个小时。对我来说,我需要删除对

的所有引用
from django.contrib.auth.models import User

然后将其替换为:

from myapp.models import MyUser as User

这是假设您的自定义 User 模型位于名为 myapp 的应用中,并且您将该模型称为 MyUser

我正在使用as User,这样我就不必更改从django.contrib.auth.models 引用User 对象的现有代码的位置。

祝你好运!

艾伦

@aviars

【讨论】:

    【解决方案3】:

    您可能应该查看官方文档中的完整示例:

    https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example

    有一些未发现的问题(例如权限处理),但至少它是有效的。

    【讨论】:

    • 谢谢,有时官方参考文献更简单,更棒
    【解决方案4】:

    来自Django docs

    您还应该为您的用户模型定义一个自定义管理器。

    【讨论】:

    • 其实我扩展了UserManager,但我得到了相同的结果。我没有展示它是为了让我的问题更简短。
    • 你应该扩展 BaseUserManager。
    • 如果我扩展 BaseUserManager 我必须覆盖大部分 AbstractUser 字段和方法,特别是如果我想使用管理站点来创建用户。我更喜欢使用 AbstractUser,只要它在 django 开发文档中提到。
    【解决方案5】:

    子类AbstractUser 已经为您处理objects = UserManager()this code on github 在第 327 行)。您无需再次在模型中定义它。

    我不确定为什么会出现该错误。但下面的配置似乎适用于我最新的开发版本。

    模型.py:

    class CustomUser(AbstractUser):
      custom_field = models.ForeignKey('OtherModel')
      # remove : objects = UserManager()
    

    【讨论】:

    • 感谢您的回复。没有这个定义,结果是一样的。我现在才测试。事实上,如果我不介意管理网站一切正常。当我在模型站点中发送第一个用户创建表单时发生错误(带有用户名密码和密码确认字段的表单)
    【解决方案6】:

    我找到了解决方案: 我不使用 UserAdmin 在管理站点中注册 CustomUser,我使用自定义 ModelAdmin。

    class CustomUserAdmin(admin.ModelAdmin):
    
      add_form = CustomUserCreationAdminForm
      add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'password1', 'password2')}
        ),
      )
      def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        return super(CustomUserAdmin, self).get_fieldsets(request, obj)
    
      def get_form(self, request, obj=None, **kwargs):
        defaults = {}
        if obj is None:
            defaults.update({
                'form': self.add_form,
                'fields': admin.util.flatten_fieldsets(self.add_fieldsets),
            })
        defaults.update(kwargs)
        return super(CustomUserAdmin, self).get_form(request, obj, **defaults)
    

    因为我想要一个不同于更新表单的创建表单,所以我重写了模型管理员的 get_form 函数,就像在 UserAdmin django code 中所做的那样。我还为我的自定义用户创建了一个自定义创建表单:CustomUserCreationForm

    我在 django-users 邮件列表中收到了可能比我的更好的回复: 从管理站点取消注册原始 User 类,然后向 UserAdmin 注册 CustomUser:

    admin.site.unregister(User)
    admin.site.register(CustomUser, UserAdmin)
    

    尚未测试。

    编辑:最后一个解决方案不起作用

    问候

    【讨论】:

      【解决方案7】:

      UserAdmin 已经注册管理User,在 contrib/auth/admin.py 的末尾

      admin.site.register(User, UserAdmin)
      

      如果您想将 UserAdmin 注册到 CustomUser,我认为您首先必须取消注册 User/UserAdmin 对:

      admin.site.unregister(User)
      

      然后注册您的新模型。鉴于模块加载顺序缺乏控制,您可以创建一个派生自UserAdmin 的类并使用它管理您的用户模型。如果我思考得当,这将每次都有效。

      【讨论】:

        猜你喜欢
        • 2013-03-21
        • 2013-06-01
        • 1970-01-01
        • 2014-04-05
        • 2013-04-20
        • 2013-07-26
        • 1970-01-01
        • 2013-12-13
        • 2013-02-24
        相关资源
        最近更新 更多