Django - 管理员中的 UserProfile m2m 字段 - 错误

Posted

技术标签:

【中文标题】Django - 管理员中的 UserProfile m2m 字段 - 错误【英文标题】:Django - UserProfile m2m field in admin - error 【发布时间】:2011-09-01 07:43:30 【问题描述】:

我的模型:

class UserProfile(models.Model):
    TYPES_CHOICES = (
        (0, _(u'teacher')),
        (1, _(u'student')),
    )
    user = models.ForeignKey(User, unique=True)
    type = models.SmallIntegerField(default=0, choices=TYPES_CHOICES, db_index=True)
    cities = models.ManyToManyField(City)
class City(models.Model):
    name = models.CharField(max_length=50)
    slug = models.SlugField(max_length=50)

在 admin.py 中:

admin.site.unregister(User) 
class UserProfileInline(admin.StackedInline):
    model = UserProfile

class UserProfileAdmin(UserAdmin):
    inlines = [UserProfileInline]

admin.site.register(User, UserProfileAdmin)

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    """Create a matching profile whenever a user object is created."""
    if created:
        profile, new = UserProfile.objects.get_or_create(user=instance)

但是当我添加新用户并选择一个城市时,我得到了那个错误:IntegrityError at /admin/auth/user/add/ (1062,“密钥“user_id”的重复条目“3””)

我的代码有什么问题?如果我不选择任何城市 - 用户已正确添加。以某种方式,用户被多次添加到 UserProfile。

【问题讨论】:

【参考方案1】:

我最近遇到了同样的问题。当你考虑它时,它实际上是完全有道理的。当您在管理员中保存带有内联的表单时,它首先保存主模型,然后继续保存每个内联。当它保存模型时,你的 post_save 信号被触发并创建一个 UserProfile 来匹配,但现在是时候保存内联了。 UserProfile 内联被认为是新的,因为它以前不存在(没有 pk 值),因此它会尝试另存为全新且不同的 UserProfile,并且您会因违反唯一约束而收到完整性错误。解决方案很简单。只需覆盖UserProfile.save

def save(self, *args, **kwargs):
    if not self.pk:
        try:
            p = UserProfile.objects.get(user=self.user)
            self.pk = p.pk
        except UserProfile.DoesNotExist:
            pass

    super(UserProfile, self).save(*args, **kwargs)

本质上,这只是检查是否存在相关用户的现有 UserProfile。如果是这样,它将这个 UserProfile 的 pk 设置为那个,以便 Django 进行更新而不是创建。

【讨论】:

谢谢!我有同样的问题。这个解决方案很有意义并且效果很好。 解释得很好。也许应该更新有关存储附加用户数据的 Django 文档以提及这一点,因为文档中提供的示例将无法正常工作。 这也可能表明 post_save 信号由于导入命名问题而被注册了两次。 dispatch_uid="unique-name-goes-here" 也可能解决了这个问题。 UserProfile的save方法在哪里?我正在使用 Django 1.6 。我在这里面临同样的问题。我必须在哪里编写此代码?

以上是关于Django - 管理员中的 UserProfile m2m 字段 - 错误的主要内容,如果未能解决你的问题,请参考以下文章

Angularjs 中的 Django 管理员

Django:删除管理员用户更改表单中的“现场查看”按钮

管理员中的 Django 自定义用户模型应用程序级别权限管理

Django 中的异常错误。创建超级用户后无法登录管理员

Django:管理员中的 AJAX/jQuery

管理员中的 Django Guardian TemplateSyntaxError