9

私のモデル:

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 に複数回追加されています。

4

1 に答える 1

20

最近、この同じ問題がありました。あなたがそれについて考えるとき、それは実際に完全に理にかなっています。admin でインラインを含むフォームを保存すると、最初にメイン モデルが保存され、次に各インラインの保存に進みます。モデルを保存すると、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 があるかどうかを確認するだけです。その場合、Django が作成ではなく更新を行うように、この UserProfile の pk をその pk に設定します。

于 2011-05-24T22:00:56.977 に答える