feat: replace versioning migrations with DocumentVersion table, renumber chain

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Trenton H
2026-04-13 14:10:48 -07:00
parent 130fcc7e42
commit fa96b4629b
9 changed files with 161 additions and 82 deletions
@@ -0,0 +1,153 @@
from __future__ import annotations
import django.core.validators
import django.db.models
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0011_alter_workflowaction_type"),
]
operations = [
migrations.CreateModel(
name="DocumentVersion",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"version_number",
models.PositiveSmallIntegerField(
help_text="Sequential version number within this document, starting at 1.",
verbose_name="version number",
),
),
(
"version_label",
models.CharField(
blank=True,
help_text="Optional short label for this version.",
max_length=64,
null=True,
verbose_name="version label",
),
),
(
"added",
models.DateTimeField(
db_index=True,
default=django.utils.timezone.now,
editable=False,
verbose_name="added",
),
),
(
"checksum",
models.CharField(
editable=False,
help_text="SHA-256 checksum of the original file for this version.",
max_length=64,
verbose_name="checksum",
),
),
(
"archive_checksum",
models.CharField(
blank=True,
editable=False,
max_length=64,
null=True,
verbose_name="archive checksum",
),
),
(
"content",
models.TextField(
blank=True,
help_text="OCR text content of this version.",
verbose_name="content",
),
),
(
"page_count",
models.PositiveIntegerField(
blank=True,
null=True,
validators=[django.core.validators.MinValueValidator(1)],
verbose_name="page count",
),
),
(
"mime_type",
models.CharField(
editable=False,
max_length=256,
verbose_name="mime type",
),
),
(
"original_filename",
models.CharField(
blank=True,
editable=False,
max_length=1024,
null=True,
verbose_name="original filename",
),
),
(
"filename",
models.FilePathField(
default=None,
editable=False,
help_text="Stored filename for this version's original file.",
max_length=1024,
null=True,
verbose_name="filename",
),
),
(
"archive_filename",
models.FilePathField(
default=None,
editable=False,
max_length=1024,
null=True,
verbose_name="archive filename",
),
),
(
"document",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="versions",
to="documents.document",
verbose_name="document",
),
),
],
options={
"verbose_name": "document version",
"verbose_name_plural": "document versions",
"ordering": ["-version_number"],
},
),
migrations.AddConstraint(
model_name="documentversion",
constraint=models.UniqueConstraint(
fields=("document", "version_number"),
name="documents_documentversion_doc_number_uniq",
),
),
]
@@ -1,37 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-26 17:08
import django.db.models.deletion
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0011_alter_workflowaction_type"),
]
operations = [
migrations.AddField(
model_name="document",
name="root_document",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="versions",
to="documents.document",
verbose_name="root document for this version",
),
),
migrations.AddField(
model_name="document",
name="version_label",
field=models.CharField(
blank=True,
help_text="Optional short label for a document version.",
max_length=64,
null=True,
verbose_name="version label",
),
),
]
@@ -6,7 +6,7 @@ from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0012_document_root_document"),
("documents", "0012_add_document_version"),
]
operations = [
@@ -1,37 +0,0 @@
# Generated by Django 5.2.11 on 2026-03-02 17:48
from django.conf import settings
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0014_savedview_visibility_to_ui_settings"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name="document",
name="version_index",
field=models.PositiveIntegerField(
blank=True,
db_index=True,
help_text="Index of this version within the root document.",
null=True,
verbose_name="version index",
),
),
migrations.AddConstraint(
model_name="document",
constraint=models.UniqueConstraint(
condition=models.Q(
("root_document__isnull", False),
("version_index__isnull", False),
),
fields=("root_document", "version_index"),
name="documents_document_root_version_index_uniq",
),
),
]
@@ -100,7 +100,7 @@ def recompute_checksums(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "0015_document_version_index_and_more"),
("documents", "0014_savedview_visibility_to_ui_settings"),
]
operations = [
@@ -28,7 +28,7 @@ def migrate_fulltext_query_field_prefixes(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "0016_sha256_checksums"),
("documents", "0015_sha256_checksums"),
]
operations = [
@@ -22,7 +22,7 @@ def migrate_saved_view_rules_forward(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "0017_migrate_fulltext_query_field_prefixes"),
("documents", "0016_migrate_fulltext_query_field_prefixes"),
]
operations = [
@@ -6,8 +6,8 @@ pytestmark = pytest.mark.search
class TestMigrateFulltextQueryFieldPrefixes(TestMigrations):
migrate_from = "0016_sha256_checksums"
migrate_to = "0017_migrate_fulltext_query_field_prefixes"
migrate_from = "0015_sha256_checksums"
migrate_to = "0016_migrate_fulltext_query_field_prefixes"
def setUpBeforeMigration(self, apps) -> None:
User = apps.get_model("auth", "User")
@@ -17,8 +17,8 @@ def _sha256(data: bytes) -> str:
class TestSha256ChecksumDataMigration(TestMigrations):
"""recompute_checksums correctly updates document checksums from MD5 to SHA256."""
migrate_from = "0015_document_version_index_and_more"
migrate_to = "0016_sha256_checksums"
migrate_from = "0014_savedview_visibility_to_ui_settings"
migrate_to = "0015_sha256_checksums"
reset_sequences = True
ORIGINAL_CONTENT = b"original file content for sha256 migration test"