From 30dec919fb0d17bf00dee5ef3a30b5748f22b4c9 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:05:18 -0800 Subject: [PATCH] Performance: skip filename checking when cf dont affect template --- src/documents/signals/handlers.py | 16 ++++++ src/documents/tests/test_file_handling.py | 68 +++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/documents/signals/handlers.py b/src/documents/signals/handlers.py index e410b54e2..4b964fafc 100644 --- a/src/documents/signals/handlers.py +++ b/src/documents/signals/handlers.py @@ -52,6 +52,7 @@ from documents.models import WorkflowRun from documents.models import WorkflowTrigger from documents.permissions import get_objects_for_user_owner_aware from documents.permissions import set_permissions_for_object +from documents.templating.utils import convert_format_str_to_template_format from documents.templating.workflows import parse_w_workflow_placeholders if TYPE_CHECKING: @@ -392,6 +393,19 @@ class CannotMoveFilesException(Exception): pass +def _filename_template_uses_custom_fields(doc: Document) -> bool: + template = None + if doc.storage_path is not None: + template = doc.storage_path.path + elif settings.FILENAME_FORMAT is not None: + template = convert_format_str_to_template_format(settings.FILENAME_FORMAT) + + if not template: + return False + + return "custom_fields" in template + + # should be disabled in /src/documents/management/commands/document_importer.py handle @receiver(models.signals.post_save, sender=CustomFieldInstance, weak=False) @receiver(models.signals.m2m_changed, sender=Document.tags.through, weak=False) @@ -402,6 +416,8 @@ def update_filename_and_move_files( **kwargs, ): if isinstance(instance, CustomFieldInstance): + if not _filename_template_uses_custom_fields(instance.document): + return instance = instance.document def validate_move(instance, old_path: Path, new_path: Path): diff --git a/src/documents/tests/test_file_handling.py b/src/documents/tests/test_file_handling.py index a1fd3d674..d649a90d2 100644 --- a/src/documents/tests/test_file_handling.py +++ b/src/documents/tests/test_file_handling.py @@ -16,6 +16,7 @@ from django.utils import timezone from documents.file_handling import create_source_path_directory from documents.file_handling import delete_empty_directories from documents.file_handling import generate_filename +from documents.file_handling import generate_unique_filename from documents.models import Correspondent from documents.models import CustomField from documents.models import CustomFieldInstance @@ -1632,6 +1633,73 @@ class TestFilenameGeneration(DirectoriesMixin, TestCase): ) +class TestCustomFieldFilenameUpdates( + DirectoriesMixin, + FileSystemAssertsMixin, + TestCase, +): + def setUp(self): + self.cf = CustomField.objects.create( + name="flavor", + data_type=CustomField.FieldDataType.STRING, + ) + self.doc = Document.objects.create( + title="document", + mime_type="application/pdf", + checksum="abc123", + ) + self.cfi = CustomFieldInstance.objects.create( + field=self.cf, + document=self.doc, + value_text="initial", + ) + return super().setUp() + + @override_settings(FILENAME_FORMAT=None) + def test_custom_field_not_in_template_skips_filename_work(self): + storage_path = StoragePath.objects.create(path="{{created}}/{{ title }}") + self.doc.storage_path = storage_path + self.doc.save() + initial_filename = generate_filename(self.doc) + Document.objects.filter(pk=self.doc.pk).update(filename=str(initial_filename)) + self.doc.refresh_from_db() + Path(self.doc.source_path).parent.mkdir(parents=True, exist_ok=True) + Path(self.doc.source_path).touch() + + with mock.patch("documents.signals.handlers.generate_unique_filename") as m: + m.side_effect = generate_unique_filename + self.cfi.value_text = "updated" + self.cfi.save() + + self.doc.refresh_from_db() + self.assertEqual(Path(self.doc.filename), initial_filename) + self.assertEqual(m.call_count, 0) + + @override_settings(FILENAME_FORMAT=None) + def test_custom_field_in_template_triggers_filename_update(self): + storage_path = StoragePath.objects.create( + path="{{ custom_fields|get_cf_value('flavor') }}/{{ title }}", + ) + self.doc.storage_path = storage_path + self.doc.save() + initial_filename = generate_filename(self.doc) + Document.objects.filter(pk=self.doc.pk).update(filename=str(initial_filename)) + self.doc.refresh_from_db() + Path(self.doc.source_path).parent.mkdir(parents=True, exist_ok=True) + Path(self.doc.source_path).touch() + + with mock.patch("documents.signals.handlers.generate_unique_filename") as m: + m.side_effect = generate_unique_filename + self.cfi.value_text = "updated" + self.cfi.save() + + self.doc.refresh_from_db() + expected_filename = Path("updated/document.pdf") + self.assertEqual(Path(self.doc.filename), expected_filename) + self.assertTrue(Path(self.doc.source_path).is_file()) + self.assertGreater(m.call_count, 0) + + class TestPathDateLocalization: """ Groups all tests related to the `localize_date` function.