Skip to content

Commit 846a493

Browse files
authored
Merge pull request #21 from now-u/reset-sequences-command
Add command to reset sequences
2 parents 1b20a7c + a120392 commit 846a493

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from django.core.management.base import BaseCommand
2+
from django.db import connection
3+
from django.apps import apps
4+
5+
6+
class Command(BaseCommand):
7+
help = "Reset PostgreSQL sequences for all models to fix duplicate key errors"
8+
9+
def add_arguments(self, parser):
10+
parser.add_argument(
11+
"--app",
12+
type=str,
13+
help="Only reset sequences for a specific app (e.g. --app causes)",
14+
)
15+
parser.add_argument(
16+
"--dry-run",
17+
action="store_true",
18+
help="Print SQL without executing it",
19+
)
20+
21+
def handle(self, *args, **options):
22+
app_filter = options.get("app")
23+
dry_run = options.get("dry_run")
24+
25+
all_models = apps.get_models()
26+
27+
if app_filter:
28+
all_models = [
29+
m for m in all_models
30+
if m._meta.app_label == app_filter
31+
]
32+
33+
if not all_models:
34+
self.stdout.write(self.style.WARNING("No models found."))
35+
return
36+
37+
with connection.cursor() as cursor:
38+
for model in all_models:
39+
table = model._meta.db_table
40+
41+
# Only process models with an integer auto primary key
42+
pk = model._meta.pk
43+
if pk is None or pk.get_internal_type() not in (
44+
"AutoField", "BigAutoField", "SmallAutoField"
45+
):
46+
continue
47+
48+
pk_col = pk.column
49+
50+
sql = f"""
51+
SELECT setval(
52+
pg_get_serial_sequence('{table}', '{pk_col}'),
53+
COALESCE((SELECT MAX({pk_col}) FROM "{table}"), 1)
54+
);
55+
"""
56+
57+
if dry_run:
58+
self.stdout.write(sql.strip())
59+
else:
60+
try:
61+
cursor.execute(sql)
62+
self.stdout.write(
63+
self.style.SUCCESS(f"✓ Reset sequence for {table}")
64+
)
65+
except Exception as e:
66+
self.stdout.write(
67+
self.style.ERROR(f"✗ Skipped {table}: {e}")
68+
)
69+
70+
if not dry_run:
71+
self.stdout.write(self.style.SUCCESS("\nAll sequences reset successfully."))

0 commit comments

Comments
 (0)