From 8b77a924dcc9814cfa51a06f64ebc3e866d54d40 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:29:42 -0700 Subject: [PATCH] Make it a matchingmodel --- .../0028_ocrtemplate_ocrtemplatezone.py | 60 ++++++++++++++----- src/documents/models.py | 29 ++------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/documents/migrations/0028_ocrtemplate_ocrtemplatezone.py b/src/documents/migrations/0028_ocrtemplate_ocrtemplatezone.py index a7235e2c3..e4ef9b8cb 100644 --- a/src/documents/migrations/0028_ocrtemplate_ocrtemplatezone.py +++ b/src/documents/migrations/0028_ocrtemplate_ocrtemplatezone.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.14 on 2026-06-16 17:36 +# Generated by Django 5.2.17 on 2026-10-20 20:29 import django.core.validators import django.db.models.deletion @@ -11,6 +11,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ ("documents", "0027_documentbarcode"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ @@ -28,16 +29,29 @@ class Migration(migrations.Migration): ), ("name", models.CharField(max_length=128, verbose_name="name")), ( - "owner", - models.ForeignKey( - blank=True, - default=None, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - verbose_name="owner", + "match", + models.CharField(blank=True, max_length=256, verbose_name="match"), + ), + ( + "matching_algorithm", + models.PositiveSmallIntegerField( + choices=[ + (0, "None"), + (1, "Any word"), + (2, "All words"), + (3, "Exact match"), + (4, "Regular expression"), + (5, "Fuzzy word"), + (6, "Automatic"), + ], + default=1, + verbose_name="matching algorithm", ), ), + ( + "is_insensitive", + models.BooleanField(default=True, verbose_name="is insensitive"), + ), ( "source_width", models.PositiveIntegerField( @@ -78,12 +92,14 @@ class Migration(migrations.Migration): models.DateTimeField(auto_now=True, verbose_name="updated"), ), ( - "document_type", + "owner", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="ocr_templates", - to="documents.documenttype", - verbose_name="document type", + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + verbose_name="owner", ), ), ( @@ -103,6 +119,7 @@ class Migration(migrations.Migration): "verbose_name": "OCR template", "verbose_name_plural": "OCR templates", "ordering": ("name",), + "abstract": False, }, ), migrations.CreateModel( @@ -276,4 +293,19 @@ class Migration(migrations.Migration): "ordering": ("template", "order"), }, ), + migrations.AddConstraint( + model_name="ocrtemplate", + constraint=models.UniqueConstraint( + fields=("name", "owner"), + name="documents_ocrtemplate_unique_name_owner", + ), + ), + migrations.AddConstraint( + model_name="ocrtemplate", + constraint=models.UniqueConstraint( + condition=models.Q(("owner__isnull", True)), + fields=("name",), + name="documents_ocrtemplate_name_uniq", + ), + ), ] diff --git a/src/documents/models.py b/src/documents/models.py index 51808f968..323cbff0c 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -2151,28 +2151,15 @@ class WorkflowRun(SoftDeleteModel): return f"WorkflowRun of {self.workflow} at {self.run_at} on {self.document}" -class OcrTemplate(ModelWithOwner): +class OcrTemplate(MatchingModel): """ - Defines a set of OCR extraction zones for a specific document type. + Defines a set of OCR extraction zones for documents with a common layout. - When a document of that type is consumed, each zone in the template is - cropped from the document image and OCR'd separately. The extracted text - is written to the configured custom field or built-in document field. + When a consumed document matches the template, each zone is cropped from + the document image and OCR'd separately. The extracted text is written to + the configured custom field or built-in document field. """ - name = models.CharField( - _("name"), - max_length=128, - ) - - document_type = models.ForeignKey( - "documents.DocumentType", - on_delete=models.CASCADE, - related_name="ocr_templates", - verbose_name=_("document type"), - db_index=True, - ) - source_width = models.PositiveIntegerField( _("source width"), validators=[MinValueValidator(1)], @@ -2220,14 +2207,10 @@ class OcrTemplate(ModelWithOwner): auto_now=True, ) - class Meta: - ordering = ("name",) + class Meta(MatchingModel.Meta): verbose_name = _("OCR template") verbose_name_plural = _("OCR templates") - def __str__(self) -> str: - return f"{self.name} ({self.document_type})" - class OcrTemplateZone(models.Model): """