Django和Postgres的get_or_create失败(重复键值违反了唯一约束)

时间:2012-02-15 16:42:39

标签: django postgresql

感谢您花时间阅读我的问题。

我有一个带有以下型号的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 个答案:

答案 0 :(得分:4)

<GridView Name="xConcerts" ItemsSource="{x:Bind Artist.UpcomingEvents, Mode=OneWay}"> <GridView.ItemTemplate> <DataTemplate x:DataType="songkick:EventExt"> <Border CornerRadius="8" Background="{ThemeResource ThemeGrayHighColorBrush}" Opacity="0.8"> <StackPanel Margin="18,2"> <TextBlock Text="{x:Bind FullDisplayDate, Converter={StaticResource FormatStringToDateDayConverter}}" Style="{ThemeResource ThemeDateBoldStyle}"/> <TextBlock Text="{x:Bind FullDisplayDate, Converter={StaticResource FormatStringToDateMonthConverter}}" Style="{ThemeResource ThemeDateBoldStyle}" Margin="0,-4,0,0"/> </StackPanel> </Border> </DataTemplate> </GridView.ItemTemplate> <GridView.ItemContainerTransitions> <TransitionCollection> <RepositionThemeTransition/> </TransitionCollection> </GridView.ItemContainerTransitions> </GridView> 中出现这些错误的另一个可能原因是其中一个搜索字段中的数据类型不匹配 - 例如,将get_or_create()而非False传递到可空字段中。 None内的.get()将无法找到它,Django将继续创建新行 - 由于PostgreSQL约束而失败。

答案 1 :(得分:3)

使用postgres时遇到了get_or_create的问题。最后,我放弃了传统的样板代码:

try:
    jobInvite  = Invite.objects.get(sender=employer.user, job=job)
except Invite.DoesNotExist:
    jobInvite  = Invite(sender=employer.user, job=job)
    jobInvite.save()
# end try

答案 2 :(得分:1)

在某些时候,您是否在Visit的个人资料字段中设置了unique = True?

看起来为postgres生成的唯一约束仍然有效。 “table_visit_profile_id_key”是它自动生成的名称,如果你正在为用户录制多次访问,它自然会导致这些错误。

如果是这种情况,您使用South来管理数据库更改吗?如果你不是,抓住它!

答案 3 :(得分:0)

PostgreSQL在一些微妙的查询中表现得有些不同,导致IntegrityError错误,特别是在您切换到 Django 1.6 之后。这是解决方案 - 您需要为每个失败的模型添加select_on_save选项:

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

这里记录了:Options.select_on_save