填写个人资料字段时,管理员中的 Django 用户创建失败

Posted

技术标签:

【中文标题】填写个人资料字段时,管理员中的 Django 用户创建失败【英文标题】:Django user creation fails in the admin when filling profile fields 【发布时间】:2012-09-28 21:17:21 【问题描述】:

我正在使用 Django 1.4.1 和 postgresql 9.1。

我需要向使用身份验证应用程序提供的用户添加配置文件,并允许管理应用程序创建和编辑此配置文件。 因此,我一直在关注文档部分Storing additional information about users:

models.py

​​>
class UserProfile(models.Model):
    user = models.OneToOneField(User)

    bio = models.TextField(null = True, blank = True)
    contact = models.TextField(null = True, blank = True)

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

post_save.connect(create_user_profile, sender=User)

settings.py

​​>
...
AUTH_PROFILE_MODULE = 'userprofile.UserProfile'
...

我还在INSTALLED_APPS 中激活了django.contrib.authdjango.contrib.admin 应用程序。

admin.py

​​>
class UserProfileInline(admin.StackedInline):
    model = UserProfile
    can_delete = False
    verbose_name_plural = 'profile'

class UserAdmin(UserAdmin):
    inlines = (UserProfileInline, )

# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

问题

现在,当我运行管理应用程序并要求添加(创建)一个新用户时,我被要求通过 两步过程创建我的用户:首先,一个页面要求只有用户名、密码(两次)和我的两个 UserProfile 字段。

如果我只输入用户名和密码(两次)并单击“保存”,我将看到该过程的第二页,它允许填写所有其他用户字段以及我的 UserProfile 字段。有一条消息说“已成功添加用户“xxxxx”。您可以在下面再次编辑它。”,幸运的是我可以从两个模型中编辑字段,它可以工作。

但是,如果我尝试在第一页的一个或两个 UserProfile 字段中输入任何内容,则提交失败并显示以下消息:

IntegrityError at /admin/auth/user/add/

duplicate key value violates unique constraint "userprofile_userprofile_user_id_key"
DETAIL:  Key (user_id)=(7) already exists.

我每次尝试都会增加“7”。

如何避免这种行为,或者如何防止配置文件字段在第一页中可编辑,但让它们在第二页中进行编辑?

完整的追溯:

环境: 请求方法:POST 请求网址:http://127.0.0.1:8000/admin/auth/user/add/ Django 版本:1.4.1 Python版本:2.7.3 已安装的应用程序: ('django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.admin', 'django.contrib.admindocs', '用户资料') 已安装的中间件: ('django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware') 追溯: get_response 中的文件“/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py” 111. 响应 = 回调(请求,*callback_args,**callback_kwargs) 包装器中的文件“/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py” 366. return self.admin_site.admin_view(view)(*args, **kwargs) _wrapped_view 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 91. 响应 = view_func(请求,*args,**kwargs) _wrapped_view_func 中的文件“/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py” 89. 响应 = view_func(请求,*args,**kwargs) 内部文件“/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py” 196. 返回视图(请求,*args,**kwargs) 在sensitive_post_parameters_wrapper 文件“/usr/local/lib/python2.7/dist-packages/django/views/decorators/debug.py” 69. 返回视图(请求,*args,**kwargs) _wrapper 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 25. 返回 bound_func(*args, **kwargs) _wrapped_view 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 91. 响应 = view_func(请求,*args,**kwargs) bound_func 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 21. 返回函数(自我,*args2,**kwargs2) 内部文件“/usr/local/lib/python2.7/dist-packages/django/db/transaction.py” 209. 返回函数(*args, **kwargs) add_view 中的文件“/usr/local/lib/python2.7/dist-packages/django/contrib/auth/admin.py” 114.extra_context) _wrapper 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 25. 返回 bound_func(*args, **kwargs) _wrapped_view 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 91. 响应 = view_func(请求,*args,**kwargs) bound_func 中的文件“/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py” 21. 返回函数(自我,*args2,**kwargs2) 内部文件“/usr/local/lib/python2.7/dist-packages/django/db/transaction.py” 209. 返回函数(*args, **kwargs) add_view 中的文件“/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py” 956. self.save_related(request, form, formsets, False) save_related 中的文件“/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py” 733. self.save_formset(请求,表单,表单集,更改=更改) save_formset 中的文件“/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py” 721. formset.save() 保存文件“/usr/local/lib/python2.7/dist-packages/django/forms/models.py” 497. return self.save_existing_objects(commit) + self.save_new_objects(commit) save_new_objects 中的文件“/usr/local/lib/python2.7/dist-packages/django/forms/models.py” 628. self.new_objects.append(self.save_new(form, commit=commit)) save_new 中的文件“/usr/local/lib/python2.7/dist-packages/django/forms/models.py” 731. obj.save() 保存文件“/usr/local/lib/python2.7/dist-packages/django/db/models/base.py” 463. self.save_base(使用=使用,force_insert=force_insert,force_update=force_update) save_base 中的文件“/usr/local/lib/python2.7/dist-packages/django/db/models/base.py” 551. 结果 = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) _insert 中的文件“/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py” 203. return insert_query(self.model, objs, fields, **kwargs) insert_query 中的文件“/usr/local/lib/python2.7/dist-packages/django/db/models/query.py” 1576. return query.get_compiler(using=using).execute_sql(return_id) execute_sql 中的文件“/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py” 910. cursor.execute(sql,参数) 执行中的文件“/usr/local/lib/python2.7/dist-packages/django/db/backends/util.py” 40. return self.cursor.execute(sql, params) 执行中的文件“/usr/local/lib/python2.7/dist-packages/django/db/backends/postgresql_psycopg2/base.py” 52.返回self.cursor.execute(查询,参数) 异常类型:/admin/auth/user/add/ 处的 IntegrityError 异常值:重复键值违反唯一约束“userprofile_userprofile_user_id_key” 详细信息:键 (user_id)=(7) 已存在。`

【问题讨论】:

你解决了吗?我遇到了这个确切的问题,并且通过在网上搜索很多人也遇到了这个问题,但没有人发布明确的解决方案。 不,我没有找到任何解决方案。由于我将是一段时间内唯一使用管理员的人,因此我现在停止搜索,抱歉。不过,我很高兴得到一个正确的答案。 我发现这里提出的解决方案有效。您必须覆盖用户配置文件类中的save 方法。 ***.com/questions/6117373/… UserProfile的save方法在哪里?我正在使用 Django 1.6 。我在这里面临同样的问题。我必须在哪里编写此代码? 【参考方案1】:

正如评论中提到的 CadentOrange,this answer 中描述了此问题的解决方案。

问题在于使用内联管理表单。以下是发生的事情:

    它保存了主模型(User) 由于 (1),Userpost_save 信号处理程序被触发,这将创建一个新的 UserProfile 对象 每个内联模型都被保存(包括另一个您的UserProfile 的副本,从而导致欺骗)。

【讨论】:

【参考方案2】:

而不是

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

做一个

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.get_or_create(user=instance)

您正在创建新的用户配置文件对象,即使是用于编辑。

【讨论】:

感谢您的想法,但不幸的是,在进行此更改 (get_or_create) 后我遇到了同样的错误。 这意味着您正在创建用户对象而不是更新它..您可以检查该代码吗? 是的,我正在创建一个用户。您希望我检查哪个代码?我认为我所有与此功能相关的代码都显示在上面,但我肯定是错的。【参考方案3】:

create_user_profile 信号和管理表单尝试创建相同的 UserProfile。您可以覆盖 LocalUserAdmin 以从添加视图中排除 UserProfileInline

class LocalUserAdmin(UserAdmin):
    inlines = (UserProfileInline, )

    def get_formsets_with_inlines(self, request, obj=None):
        for inline in self.get_inline_instances(request, obj):
            # hide MyInline in the add view
            if isinstance(inline, UserProfileInline) and obj is None:
                continue
            yield inline.get_formset(request, obj), inline

见https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_formsets_with_inlines

【讨论】:

以上是关于填写个人资料字段时,管理员中的 Django 用户创建失败的主要内容,如果未能解决你的问题,请参考以下文章

Django 管理站点:添加用户页面如何工作(编辑更多字段)?

Django Admin预先填写用户的电子邮件

我们如何在 django 中更改现有用户表中的字段名称

Django 更新配置文件

使用 Django 表单编辑图像字段

基于选择的 Django 模板/ChoiceField 显示字段