Django / Postgres:返回错误:重复键值违反了唯一约束

时间:2018-03-07 21:50:06

标签: django postgresql

我已经使用我正在处理的项目多次出现此问题,虽然我使用了我在此站点上找到的“python manage.py sqlsequencereset”修复程序,但它可以工作一段时间,并且然后再次开始抛出错误。

我不断得到的错误非常简单:

IntegrityError at /projects/v/portola/planting-sites/new/
duplicate key value violates unique constraint "urbanforest_plantingsite_pkey"
DETAIL:  Key (id)=(194016) already exists.

在我看来,我有:

form = PlantingSiteForm(request.POST)
if form.is_valid():
    f = form.save(commit=False)
    if PlantingSite.objects.all().exists():
        last_planting_site = PlantingSite.objects.all().order_by('-created_at')[0]
        f.id_planting_site = last_planting_site.id_planting_site
        f.id_planting_site += 1
    else:
        f.id_planting_site = 100000
    if request.POST.get('neighborhood_id'):
        f.neighborhood = Neighborhood.objects.filter(id_neighborhood=request.POST.get('neighborhood_id'))[0]
    if request.POST.get('district_id'):
        f.district = District.objects.filter(id_district=request.POST.get('district_id'))[0]
    if request.POST.get('basin_type_id'):
        f.basin_type = BasinType.objects.filter(id_basin_type=request.POST.get('basin_type_id'))[0]
    if request.POST.get('aspect_id'):
        f.aspect = Aspect.objects.filter(id_aspect=request.POST.get('aspect_id'))[0]
    if request.POST.get('orientation_id'):
        f.orientation = Orientation.objects.filter(id_orientation=request.POST.get('orientation_id'))[0]
    if request.POST.get('hardscape_damage_id'):
        f.hardscape_damage = HardscapeDamage.objects.filter(id_hardscape_damage=request.POST.get('hardscape_damage_id'))[0]
    if request.POST.get('status_id'):
        f.status = PlantingSiteStatus.objects.filter(id_planting_site_status=request.POST.get('status_id'))[0]
    else:
        f.status = PlantingSiteStatus.objects.filter(id_planting_site_status=9)[0]
    if f.zipcode:
        f.property_zipcode = f.zipcode
    f.created_by_fuf = True
    f.created_by = request.user 
    f.save()

我现在已经完成了几次sqlsequencereset,然后在几周后错误返回。我没有导入任何数据,但我的同事正在现场使用他们的手机创建新对象,一次一个。

运行sqlsequencereset会得到这段代码:

SELECT setval(pg_get_serial_sequence('"urbanforest_plantingsite"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "urbanforest_plantingsite";

我应该运行更具体的东西吗?我对Postgres不太熟悉,因为我刚刚使用Django命令处理所有数据库调用。

编辑:有一点需要补充,我发现运行sqlsequencereset会生成用于调整sql调用的CODE,它实际上并没有运行它。所以我跑了:
python manage.py sqlsequencereset urbanforest | python manage.py dbshel​​l 注入代码并重建表格。

不幸的是,几分钟后我收到了同样的错误。

1 个答案:

答案 0 :(得分:0)

所以我通过将网站创建移动到while循环来修复此问题(至少目前为止)。我认为问题是Django如何通过使用模型表单来处理创建对象。由于您使用form.save(commit = False)创建对象并将其保存到内存中,因此在将对象添加到数据库之前将其他字段添加到对象中可能会遇到问题。

所以现在,至少,这解决了这个问题:

while True:
        try:    
            form = PlantingSiteForm(request.POST)
                if form.is_valid():
                    f = form.save(commit=False)
                    if PlantingSite.objects.all().exists():
                        last_planting_site = PlantingSite.objects.all().order_by('-created_at')[0]
                        f.id_planting_site = last_planting_site.id_planting_site
                        f.id_planting_site += 1
                    else:
                        f.id_planting_site = 100000
                    if request.POST.get('neighborhood_id'):
                        f.neighborhood = Neighborhood.objects.filter(id_neighborhood=request.POST.get('neighborhood_id'))[0]
                    if request.POST.get('district_id'):
                        f.district = District.objects.filter(id_district=request.POST.get('district_id'))[0]
                    if request.POST.get('basin_type_id'):
                        f.basin_type = BasinType.objects.filter(id_basin_type=request.POST.get('basin_type_id'))[0]
                    if request.POST.get('aspect_id'):
                        f.aspect = Aspect.objects.filter(id_aspect=request.POST.get('aspect_id'))[0]
                    if request.POST.get('orientation_id'):
                        f.orientation = Orientation.objects.filter(id_orientation=request.POST.get('orientation_id'))[0]
                    if request.POST.get('hardscape_damage_id'):
                        f.hardscape_damage = HardscapeDamage.objects.filter(id_hardscape_damage=request.POST.get('hardscape_damage_id'))[0]
                    if request.POST.get('status_id'):
                        f.status = PlantingSiteStatus.objects.filter(id_planting_site_status=request.POST.get('status_id'))[0]
                    else:
                        f.status = PlantingSiteStatus.objects.filter(id_planting_site_status=9)[0]
                    if f.zipcode:
                        f.property_zipcode = f.zipcode
                    f.created_by_fuf = True
                    f.created_by = request.user 
                    f.save()
        except IntegrityError:
            sleep(random.uniform(0.001, 0.5)) # chill out, try again
            messages.success(request, "Still creating previous site, trying again...")
            continue

因此它尝试创建对象,如果由于完整性错误而失败,它会在一秒钟内休眠,然后再次尝试。到目前为止,这么好,我的同事在现场使用它,我还没有看到任何错误。