feat: remove effective_content machinery — Document.content is always current

- EffectiveContentFilter and TitleContentFilter simplified to query content directly
- Remove FieldError fallback try/except blocks; effective_content annotation gone
- add_to_index handler no longer calls get_effective_content()
- _build_tantivy_doc and add_or_update drop effective_content parameter
- Remove compatibility stubs from versioning.py (EffectiveDocumentResolution,
  resolve_effective_document_by_pk, get_root_document, get_latest_version_for_root)
- Remove get_effective_content() shim from Document model
- Remove DocumentVersion.modified compatibility property

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Trenton H
2026-04-14 07:13:05 -07:00
co-authored by Claude Sonnet 4.6
parent f18b56ed8a
commit 2116ea3329
5 changed files with 11 additions and 108 deletions
+5 -19
View File
@@ -10,7 +10,6 @@ from typing import TYPE_CHECKING
from typing import Any
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldError
from django.db.models import Case
from django.db.models import CharField
from django.db.models import Count
@@ -172,16 +171,10 @@ class TitleContentFilter(Filter):
logger.warning(
"Deprecated document filter parameter 'title_content' used; use `text` instead.",
)
try:
return qs.filter(
Q(title__icontains=value) | Q(effective_content__icontains=value),
)
except FieldError:
return qs.filter(
Q(title__icontains=value) | Q(content__icontains=value),
)
else:
return qs
return qs.filter(
Q(title__icontains=value) | Q(content__icontains=value),
)
return qs
@extend_schema_field(serializers.CharField)
@@ -190,14 +183,7 @@ class EffectiveContentFilter(Filter):
value = value.strip() if isinstance(value, str) else value
if not value:
return qs
try:
return qs.filter(
**{f"effective_content__{self.lookup_expr}": value},
)
except FieldError:
return qs.filter(
**{f"content__{self.lookup_expr}": value},
)
return qs.filter(**{f"content__{self.lookup_expr}": value})
@extend_schema_field(serializers.BooleanField)
-19
View File
@@ -336,16 +336,6 @@ class DocumentVersion(DocumentBase):
def source_file(self):
return self.source_path.open("rb")
@property
def modified(self):
"""Compatibility shim for conditionals.py which expects .modified.
DocumentVersion tracks creation time via added; callers that need a
last-modified value for HTTP caching use this property.
Task 9 will refactor conditionals.py to stop using this path.
"""
return self.added
class Document(DocumentBase, SoftDeleteModel, ModelWithOwner): # type: ignore[django-manager-missing]
MAX_STORED_FILENAME_LENGTH: Final[int] = 1024
@@ -525,15 +515,6 @@ class Document(DocumentBase, SoftDeleteModel, ModelWithOwner): # type: ignore[d
def created_date(self):
return self.created
def get_effective_content(self) -> str:
"""Return the content to use for search indexing and matching.
This is a compatibility shim; since DocumentVersion now holds per-version
content, the Document.content cache field already reflects the latest version.
Task 9 will remove the callers of this method.
"""
return self.content
def add_nested_tags(self, tags) -> None:
tag_ids = set()
for tag in tags:
+5 -20
View File
@@ -184,7 +184,6 @@ class WriteBatch:
def add_or_update(
self,
document: Document,
effective_content: str | None = None,
) -> None:
"""
Add or update a document in the batch.
@@ -195,11 +194,9 @@ class WriteBatch:
Args:
document: Django Document instance to index
effective_content: Override document.content for indexing (used when
re-indexing with newer OCR text from document versions)
"""
self.remove(document.pk)
doc = self._backend._build_tantivy_doc(document, effective_content)
doc = self._backend._build_tantivy_doc(document)
self._writer.add_document(doc)
def remove(self, doc_id: int) -> None:
@@ -275,16 +272,9 @@ class TantivyBackend:
def _build_tantivy_doc(
self,
document: Document,
effective_content: str | None = None,
) -> tantivy.Document:
"""Build a tantivy Document from a Django Document instance.
``effective_content`` overrides ``document.content`` for indexing —
used when re-indexing a root document with a newer version's OCR text.
"""
content = (
effective_content if effective_content is not None else document.content
)
"""Build a tantivy Document from a Django Document instance."""
content = document.content
doc = tantivy.Document()
@@ -395,7 +385,6 @@ class TantivyBackend:
def add_or_update(
self,
document: Document,
effective_content: str | None = None,
) -> None:
"""
Add or update a single document with file locking.
@@ -405,11 +394,10 @@ class TantivyBackend:
Args:
document: Django Document instance to index
effective_content: Override document.content for indexing
"""
self._ensure_open()
with self.batch_update(lock_timeout=5.0) as batch:
batch.add_or_update(document, effective_content)
batch.add_or_update(document)
def remove(self, doc_id: int) -> None:
"""
@@ -805,10 +793,7 @@ class TantivyBackend:
try:
writer = new_index.writer()
for document in iter_wrapper(documents):
doc = self._build_tantivy_doc(
document,
document.get_effective_content(),
)
doc = self._build_tantivy_doc(document)
writer.add_document(doc)
writer.commit()
new_index.reload()
+1 -4
View File
@@ -782,10 +782,7 @@ def cleanup_user_deletion(sender, instance: User | Group, **kwargs) -> None:
def add_to_index(sender, document, **kwargs) -> None:
from documents.search import get_backend
get_backend().add_or_update(
document,
effective_content=document.get_effective_content(),
)
get_backend().add_or_update(document)
def run_workflows_added(
-46
View File
@@ -41,52 +41,6 @@ def get_version_by_pk(doc: Document, version_pk: int) -> DocumentVersion | None:
return DocumentVersion.objects.filter(pk=version_pk, document=doc).first()
@dataclass(frozen=True, slots=True)
class EffectiveDocumentResolution:
"""Compatibility shim for conditionals.py callers that access .document.
Task 9 will refactor these callers to use VersionResolution.version directly.
"""
document: DocumentVersion | None
def resolve_effective_document_by_pk(
pk: int,
request: Any,
) -> EffectiveDocumentResolution:
"""Resolve the effective DocumentVersion by document pk and request params.
This is a compatibility stub used by conditionals.py; Task 9 will refactor
the callers to use resolve_requested_version directly.
"""
try:
doc = Document.objects.get(pk=pk)
except Document.DoesNotExist:
return EffectiveDocumentResolution(document=None)
resolution = resolve_requested_version(doc, request)
return EffectiveDocumentResolution(document=resolution.version)
def get_root_document(doc: Document) -> Document:
"""Return the root document.
In the new model, every Document IS the root. This is a compatibility stub
used by bulk_edit.py; Task 10 will refactor the callers.
"""
return doc
def get_latest_version_for_root(doc: Document) -> Document:
"""Return the document to use as the version source.
In the new model, DocumentVersion holds per-version files. This stub
returns the document itself so that bulk_edit callers that have not yet
been updated to the new model do not crash. Task 10 will replace this.
"""
return doc
def resolve_requested_version(
doc: Document,
request: Any,