Django - UserProfile m2m поле в админке - ошибка - PullRequest
9 голосов
/ 25 мая 2011

Мои модели:

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 в / admin / auth / user / add / (1062, "Дублирующая запись '3' для ключа 'user_id'")

Что не так с моим кодом? Если я не выберу какой-либо город - пользователь будет добавлен правильно. Каким-то образом пользователь добавляется в UserProfile более одного раза.

1 Ответ

20 голосов
/ 25 мая 2011

У меня недавно была такая же проблема. Это действительно имеет смысл, когда вы думаете об этом. Когда вы сохраняете форму со встроенными в администраторе, она сначала сохраняет основную модель, а затем переходит к сохранению каждой встроенной. Когда он сохраняет модель, ваш сигнал 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 для данного пользователя. Если это так, он устанавливает pk этого UserProfile на тот, чтобы Django делал обновление вместо create.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...