83 lines
4.2 KiB
Plaintext
83 lines
4.2 KiB
Plaintext
# documentation/models.py
|
|
from django.conf import settings
|
|
from django.db import models
|
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
from django.contrib.contenttypes.models import ContentType
|
|
import uuid
|
|
|
|
class NoteType(models.TextChoices):
|
|
ADMISSION = "ADMISSION", "Admission Note"
|
|
PROGRESS = "PROGRESS", "Progress Note"
|
|
DISCHARGE = "DISCHARGE", "Discharge Summary"
|
|
RADIOLOGY_REPORT = "RADIOLOGY_REPORT", "Radiology Report"
|
|
LAB_REPORT = "LAB_REPORT", "Laboratory Narrative"
|
|
PROCEDURE = "PROCEDURE", "Procedure Note"
|
|
ANESTHESIA = "ANESTHESIA", "Anesthesia Note"
|
|
OTHER = "OTHER", "Other"
|
|
|
|
class Document(models.Model):
|
|
"""
|
|
Canonical clinical document (note/report).
|
|
Stores content, metadata, provenance, and links to any domain object.
|
|
"""
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
tenant = models.ForeignKey("core.Tenant", on_delete=models.CASCADE, related_name="documents")
|
|
patient = models.ForeignKey("core.Patient", on_delete=models.CASCADE, related_name="documents")
|
|
encounter = models.ForeignKey("core.Encounter", on_delete=models.SET_NULL, null=True, blank=True, related_name="documents")
|
|
|
|
doc_type = models.CharField(max_length=40, choices=NoteType.choices)
|
|
title = models.CharField(max_length=255)
|
|
status = models.CharField(max_length=20, default="final") # draft | amended | final | entered-in-error
|
|
authored_at = models.DateTimeField(auto_now_add=True)
|
|
authored_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name="documents_authored")
|
|
signed_at = models.DateTimeField(null=True, blank=True)
|
|
signed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="documents_signed")
|
|
|
|
# Content
|
|
# Store both rich text and structured JSON to support templates, tokens, smart fields.
|
|
body_markdown = models.TextField(blank=True, default="")
|
|
body_json = models.JSONField(blank=True, null=True) # optional structured representation
|
|
|
|
# FHIR mapping hints (optional)
|
|
fhir_profile = models.CharField(max_length=120, blank=True, default="") # e.g., Composition/DiagnosticReport
|
|
code = models.CharField(max_length=64, blank=True, default="") # LOINC/SNOMED if used
|
|
|
|
# Full-text search (enable GIN index in migration)
|
|
search_vector = models.TextField(blank=True, default="") # or use a dedicated SearchVector field
|
|
|
|
# Soft flags
|
|
is_confidential = models.BooleanField(default=False)
|
|
is_amendment = models.BooleanField(default=False)
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class DocumentVersion(models.Model):
|
|
document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="versions")
|
|
version = models.PositiveIntegerField()
|
|
snapshot_markdown = models.TextField(blank=True, default="")
|
|
snapshot_json = models.JSONField(blank=True, null=True)
|
|
changed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
|
|
changed_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
class Meta:
|
|
unique_together = [("document", "version")]
|
|
ordering = ["-version"]
|
|
|
|
class DocumentLink(models.Model):
|
|
"""
|
|
Generic relation to ANY object (lab order, study, admission, procedure, etc.)
|
|
Allows many-to-many linking without embedding foreign keys in every domain app.
|
|
"""
|
|
document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="links")
|
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
|
object_id = models.CharField(max_length=64)
|
|
target = GenericForeignKey("content_type", "object_id")
|
|
role = models.CharField(max_length=40, blank=True, default="context") # context | source | result | followup
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
class DocumentAttachment(models.Model):
|
|
document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="attachments")
|
|
file = models.FileField(upload_to="documents/%Y/%m/")
|
|
title = models.CharField(max_length=255, blank=True, default="")
|
|
created_at = models.DateTimeField(auto_now_add=True) |