Ошибка get_or_create с Django и Postgres (двойное значение ключа нарушает ограничение уникальности) - PullRequest
9 голосов
/ 15 февраля 2012

Спасибо, что нашли время прочитать мой вопрос.

У меня есть приложение django со следующей моделью:

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

class Visit(models.Model):
    profile = models.ForeignKey(UserProfile)
    date = models.DateField(auto_now_add=True, db_index=True)
    ip = models.IPAddressField()
    class Meta:
        unique_together = ('profile', 'date', 'ip')

В виде:

profile = get_object_or_404(Profile, pk = ...)
get, create = Visit.objects.get_or_create(profile=profile, date=now.date(), ip=request.META['REMOTE_ADDR'])
if create: DO SOMETHING

Все работает нормально, за исключением того, что журналы Postgres заполнены ошибками дублирования ключа:

2012-02-15 14:13:44 CET ERROR:  duplicate key value violates unique constraint "table_visit_profile_id_key"
2012-02-15 14:13:44 CET STATEMENT:  INSERT INTO "table_visit" ("profile_id", "date", "ip") VALUES (1111, E'2012-02-15', E'xx.xx.xxx.xxx') RETURNING "table_visit"."id"

Пробовал другое решение, например

from django.db import transaction 
from django.db import IntegrityError

@transaction.commit_on_success
def my_get_or_create(prof, ip):    
    try:
        object = Visit.objects.create(profile=prof, date=datetime.now().date(), ip=ip)
    except IntegrityError:
        transaction.commit()
        object = Visit.objects.get(profile=prof, date=datetime.now().date(), ip=ip)
    return object

....

created = my_get_or_create(prof, request.META['REMOTE_ADDR'])
if created: DO SOMETHING

Это помогает только для MySQL?Кто-нибудь знает, как избежать повторяющихся ошибок значения ключа для postgres?

Ответы [ 4 ]

4 голосов
/ 20 апреля 2016

Другой возможной причиной этих ошибок в get_or_create() является несоответствие типов данных в одном из полей поиска - например, передача False вместо None в пустое поле..get() внутри .get_or_create() не найдет его, и Django продолжит создание новой строки - что не удастся из-за ограничений PostgreSQL.

3 голосов
/ 10 декабря 2014

У меня были проблемы с get_or_create при использовании postgres. В конце концов я отказался от стандартного кода:

try:
    jobInvite  = Invite.objects.get(sender=employer.user, job=job)
except Invite.DoesNotExist:
    jobInvite  = Invite(sender=employer.user, job=job)
    jobInvite.save()
# end try
1 голос
/ 15 февраля 2012

У вас когда-нибудь был уникальный = True установлен в поле профиля Визита?

Похоже, что для postgres было создано уникальное ограничение, которое все еще действует. "table_visit_profile_id_key" - это то, чем будет автоматически сгенерированное имя, и, естественно, это вызовет эти ошибки, если вы записываете несколько посещений для пользователя.

Если это так, используете ли вы Юг для управления изменениями базы данных? Если нет, возьмите его!

0 голосов
/ 21 ноября 2013

PostgreSQL ведет себя несколько иначе в некоторых тонких запросах, что приводит к IntegrityError ошибкам, особенно после переключения на Django 1.6 .Вот решение - вам нужно добавить опцию select_on_save для каждой неисправной модели:

class MyModel(models.Model):
     ...
     class Meta:
         select_on_save = True

Это задокументировано здесь: Options.select_on_save

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