diff --git a/procrastinate/contrib/django/migrations_magic.py b/procrastinate/contrib/django/migrations_magic.py index 3ee28fa1d..39236055c 100644 --- a/procrastinate/contrib/django/migrations_magic.py +++ b/procrastinate/contrib/django/migrations_magic.py @@ -39,6 +39,10 @@ def __init__(self): self.migrations = { mig.name: mig for mig in make_migrations(sql_migrations=sql_migrations) } + from .static_migrations import static_migrations + + for name, migration in static_migrations.items(): + self.migrations[name] = migration # Necessary for Pyright def find_module(self, fullname, path=None): diff --git a/procrastinate/contrib/django/models.py b/procrastinate/contrib/django/models.py index ef7b1309c..505eb1b97 100644 --- a/procrastinate/contrib/django/models.py +++ b/procrastinate/contrib/django/models.py @@ -52,6 +52,7 @@ class ProcrastinateJob(ProcrastinateReadOnlyModelMixin, models.Model): "succeeded", "failed", ) + id = models.BigAutoField(primary_key=True) queue_name = models.CharField(max_length=128) task_name = models.CharField(max_length=128) lock = models.TextField(unique=True, blank=True, null=True) @@ -78,6 +79,7 @@ class ProcrastinateEvent(ProcrastinateReadOnlyModelMixin, models.Model): "cancelled", "scheduled", ) + id = models.BigAutoField(primary_key=True) job = models.ForeignKey(ProcrastinateJob, on_delete=models.CASCADE) type = models.CharField(max_length=32, choices=[(e, e) for e in TYPES]) at = models.DateTimeField(blank=True, null=True) @@ -90,6 +92,7 @@ class Meta: # type: ignore class ProcrastinatePeriodicDefer(models.Model): + id = models.BigAutoField(primary_key=True) task_name = models.CharField(max_length=128) defer_timestamp = models.BigIntegerField(blank=True, null=True) job = models.ForeignKey( diff --git a/procrastinate/contrib/django/static_migrations.py b/procrastinate/contrib/django/static_migrations.py new file mode 100644 index 000000000..f63130d86 --- /dev/null +++ b/procrastinate/contrib/django/static_migrations.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +from typing import ClassVar + +from django.db import migrations, models + +import procrastinate.contrib.django.models + +static_migrations = {} + + +class Migration(migrations.Migration): + initial = True + + dependencies: ClassVar = [ + ("procrastinate", "0024_job_id_bigint"), + ] + + operations: ClassVar = [ + migrations.CreateModel( + name="ProcrastinateEvent", + fields=[ + ("id", models.BigAutoField(primary_key=True, serialize=False)), + ( + "type", + models.CharField( + choices=[ + ("deferred", "deferred"), + ("started", "started"), + ("deferred_for_retry", "deferred_for_retry"), + ("failed", "failed"), + ("succeeded", "succeeded"), + ("cancelled", "cancelled"), + ("scheduled", "scheduled"), + ], + max_length=32, + ), + ), + ("at", models.DateTimeField(blank=True, null=True)), + ], + options={ + "db_table": "procrastinate_events", + "managed": False, + }, + bases=( + procrastinate.contrib.django.models.ProcrastinateReadOnlyModelMixin, + models.Model, + ), + ), + migrations.CreateModel( + name="ProcrastinateJob", + fields=[ + ("id", models.BigAutoField(primary_key=True, serialize=False)), + ("queue_name", models.CharField(max_length=128)), + ("task_name", models.CharField(max_length=128)), + ("lock", models.TextField(blank=True, null=True, unique=True)), + ("args", models.JSONField()), + ( + "status", + models.CharField( + choices=[ + ("todo", "todo"), + ("doing", "doing"), + ("succeeded", "succeeded"), + ("failed", "failed"), + ], + max_length=32, + ), + ), + ("scheduled_at", models.DateTimeField(blank=True, null=True)), + ("attempts", models.IntegerField()), + ("queueing_lock", models.TextField(blank=True, null=True, unique=True)), + ], + options={ + "db_table": "procrastinate_jobs", + "managed": False, + }, + bases=( + procrastinate.contrib.django.models.ProcrastinateReadOnlyModelMixin, + models.Model, + ), + ), + migrations.CreateModel( + name="ProcrastinatePeriodicDefer", + fields=[ + ("id", models.BigAutoField(primary_key=True, serialize=False)), + ("task_name", models.CharField(max_length=128)), + ("defer_timestamp", models.BigIntegerField(blank=True, null=True)), + ("periodic_id", models.CharField(max_length=128)), + ], + options={ + "db_table": "procrastinate_periodic_defers", + "managed": False, + }, + ), + ] + + +static_migrations["0025_add_models"] = Migration diff --git a/tests/migration/test_migration.py b/tests/migration/test_migration.py index c60e01bfa..5d4bd58cb 100644 --- a/tests/migration/test_migration.py +++ b/tests/migration/test_migration.py @@ -4,6 +4,7 @@ import pathlib import pytest +from django.core import management from django.db import connection from migra import Migration from sqlalchemy.pool import NullPool @@ -83,3 +84,7 @@ def test_django_migrations_run_properly(django_db): # At this point, with the db fixture, we have all migrations applied with connection.cursor() as cursor: cursor.execute("SELECT * FROM procrastinate_jobs") + + +def test_no_missing_django_migration(django_db): + management.call_command("makemigrations", "procrastinate", dry_run=True, check=True)