【发布时间】:2018-08-16 03:20:08
【问题描述】:
我一直在从事的一个项目中多次出现此问题,虽然我使用了我在此站点上找到的“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 调用的代码,它实际上并没有运行它。所以我跑了:
python manage.py sqlsequencereset urbanforest | python manage.py dbshell
它注入了代码并重建了表。
不幸的是,几分钟后我收到了同样的错误。
【问题讨论】:
-
你有竞争条件;如果两个人同时尝试创建
PlantingSite,他们会得到相同的 ID。为什么要手动增加 ID?此外,仅仅看一眼代码,您正在做的很多事情似乎都可以通过表单的save来完成。 -
只有两个人在现场使用该应用程序,而且他们很少同时在那里,所以希望现在比赛条件不是问题,我不知道该怎么办做以解决这个长期问题。对于递增的 ID,我只想要一个不直接连接到 PK 的面向公众的 ID,以防万一。
-
如果
order_by('-created_at')返回的对象不一定是ID最高的对象,则可能不是竞争条件。除非您有充分的理由使用手动 ID,否则它只会徒劳无功。您可以使用F表达式或select_for_update来考虑并发性,并以不同的方式进行查询以确保它确实获得最高ID,但这似乎是多余的。
标签: django postgresql