Marwan Alwali ab2c4a36c5 update
2025-10-02 10:13:03 +03:00

576 lines
17 KiB
Python

"""
Radiology app admin configuration.
"""
from django.contrib import admin
from django.utils.html import format_html
from django.urls import reverse
from django.utils.safestring import mark_safe
from .models import (
ImagingStudy, ImagingSeries, DICOMImage,
RadiologyReport, ReportTemplate, ImagingOrder
)
class ImagingSeriesInline(admin.TabularInline):
"""
Inline admin for imaging series.
"""
model = ImagingSeries
extra = 0
fields = [
'series_number', 'modality', 'series_description',
'number_of_instances', 'series_size', 'image_quality'
]
readonly_fields = ['number_of_instances', 'series_size']
class DICOMImageInline(admin.TabularInline):
"""
Inline admin for DICOM images.
"""
model = DICOMImage
extra = 0
fields = [
'instance_number', 'rows', 'columns',
'file_size', 'image_quality', 'processed'
]
readonly_fields = ['file_size']
@admin.register(ImagingStudy)
class ImagingStudyAdmin(admin.ModelAdmin):
"""
Admin interface for imaging studies.
"""
list_display = [
'accession_number', 'patient_name', 'modality',
'study_description', 'study_datetime', 'status',
'priority', 'radiologist', 'number_of_series'
]
list_filter = [
'tenant', 'modality', 'status', 'priority',
'study_datetime', 'image_quality', 'completion_status'
]
search_fields = [
'accession_number', 'study_instance_uid',
'patient__first_name', 'patient__last_name',
'patient__mrn', 'study_description'
]
readonly_fields = [
'study_id', 'accession_number', 'study_datetime',
'number_of_series', 'number_of_instances', 'study_size',
'created_at', 'updated_at'
]
fieldsets = [
('Study Information', {
'fields': [
'study_id', 'study_instance_uid', 'accession_number',
'tenant', 'patient'
]
}),
('Study Details', {
'fields': [
'modality', 'study_description', 'body_part', 'study_datetime'
]
}),
('Clinical Information', {
'fields': [
'clinical_indication', 'clinical_history', 'diagnosis_code',
'referring_physician', 'radiologist'
]
}),
('Status and Priority', {
'fields': [
'status', 'priority', 'image_quality', 'completion_status'
]
}),
('Technical Parameters', {
'fields': [
'kvp', 'mas', 'exposure_time', 'slice_thickness'
],
'classes': ['collapse']
}),
('Equipment Information', {
'fields': [
'station_name', 'manufacturer', 'model_name'
],
'classes': ['collapse']
}),
('Study Metrics', {
'fields': [
'number_of_series', 'number_of_instances', 'study_size'
],
'classes': ['collapse']
}),
('PACS Information', {
'fields': [
'pacs_location', 'archived', 'archive_location'
],
'classes': ['collapse']
}),
('Related Information', {
'fields': [
'encounter', 'imaging_order'
],
'classes': ['collapse']
}),
('Metadata', {
'fields': [
'created_at', 'updated_at', 'created_by'
],
'classes': ['collapse']
})
]
inlines = [ImagingSeriesInline]
date_hierarchy = 'study_datetime'
def patient_name(self, obj):
"""Display patient name."""
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def get_queryset(self, request):
"""Filter by user's tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
qs = qs.filter(tenant=request.user.tenant)
return qs.select_related('patient', 'radiologist', 'referring_physician')
@admin.register(ImagingSeries)
class ImagingSeriesAdmin(admin.ModelAdmin):
"""
Admin interface for imaging series.
"""
list_display = [
'series_number', 'study_accession', 'modality',
'series_description', 'series_datetime', 'number_of_instances',
'image_quality'
]
list_filter = [
'modality', 'series_datetime', 'image_quality',
'patient_position', 'contrast_route'
]
search_fields = [
'series_instance_uid', 'series_description',
'study__accession_number', 'study__patient__first_name',
'study__patient__last_name'
]
readonly_fields = [
'series_id', 'series_datetime', 'number_of_instances',
'series_size', 'created_at', 'updated_at'
]
fieldsets = [
('Series Information', {
'fields': [
'series_id', 'series_instance_uid', 'series_number',
'study'
]
}),
('Series Details', {
'fields': [
'modality', 'series_description', 'protocol_name',
'series_date', 'series_time', 'series_datetime'
]
}),
('Technical Parameters', {
'fields': [
'slice_thickness', 'spacing_between_slices',
'pixel_spacing', 'image_orientation'
]
}),
('Body Part and Position', {
'fields': [
'body_part', 'patient_position'
]
}),
('Contrast Information', {
'fields': [
'contrast_agent', 'contrast_route'
]
}),
('Series Metrics', {
'fields': [
'number_of_instances', 'series_size', 'image_quality'
]
}),
('Metadata', {
'fields': [
'created_at', 'updated_at'
],
'classes': ['collapse']
})
]
inlines = [DICOMImageInline]
def study_accession(self, obj):
"""Display study accession number."""
return obj.study.accession_number
study_accession.short_description = 'Study'
def get_queryset(self, request):
"""Filter by user's tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
qs = qs.filter(study__tenant=request.user.tenant)
return qs.select_related('study__patient')
@admin.register(DICOMImage)
class DICOMImageAdmin(admin.ModelAdmin):
"""
Admin interface for DICOM images.
"""
list_display = [
'instance_number', 'series_info', 'sop_class_uid',
'rows', 'columns', 'file_size_mb', 'image_quality',
'processed', 'archived'
]
list_filter = [
'sop_class_uid', 'image_quality', 'processed',
'archived', 'content_date'
]
search_fields = [
'sop_instance_uid', 'series__series_instance_uid',
'series__study__accession_number'
]
readonly_fields = [
'image_id', 'file_size_mb', 'acquisition_datetime',
'created_at', 'updated_at'
]
fieldsets = [
('Image Information', {
'fields': [
'image_id', 'sop_instance_uid', 'instance_number',
'series'
]
}),
('Image Details', {
'fields': [
'image_type', 'sop_class_uid'
]
}),
('Image Dimensions', {
'fields': [
'rows', 'columns', 'bits_allocated', 'bits_stored'
]
}),
('Image Position and Orientation', {
'fields': [
'image_position', 'image_orientation', 'slice_location'
]
}),
('Window/Level Settings', {
'fields': [
'window_center', 'window_width'
]
}),
('File Information', {
'fields': [
'file_path', 'file_size', 'file_size_mb',
'transfer_syntax_uid'
]
}),
('Content Information', {
'fields': [
'content_date', 'content_time', 'acquisition_datetime'
]
}),
('Quality and Status', {
'fields': [
'image_quality', 'processed', 'archived'
]
}),
('Metadata', {
'fields': [
'created_at', 'updated_at'
],
'classes': ['collapse']
})
]
def series_info(self, obj):
"""Display series information."""
return f"Series {obj.series.series_number} - {obj.series.study.accession_number}"
series_info.short_description = 'Series'
def get_queryset(self, request):
"""Filter by user's tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
qs = qs.filter(series__study__tenant=request.user.tenant)
return qs.select_related('series__study')
@admin.register(RadiologyReport)
class RadiologyReportAdmin(admin.ModelAdmin):
"""
Admin interface for radiology reports.
"""
list_display = [
'study_accession', 'patient_name', 'radiologist',
'status', 'critical_finding', 'finalized_datetime',
'turnaround_time'
]
list_filter = [
'status', 'critical_finding', 'critical_communicated',
'finalized_datetime', 'radiologist'
]
search_fields = [
'study__accession_number', 'study__patient__first_name',
'study__patient__last_name', 'radiologist__first_name',
'radiologist__last_name', 'findings', 'impression'
]
readonly_fields = [
'report_id', 'report_length', 'turnaround_time',
'created_at', 'updated_at'
]
fieldsets = [
('Report Information', {
'fields': [
'report_id', 'study', 'template_used'
]
}),
('Radiologist Information', {
'fields': [
'radiologist', 'dictated_by', 'transcribed_by'
]
}),
('Report Content', {
'fields': [
'clinical_history', 'technique', 'findings',
'impression', 'recommendations'
]
}),
('Report Status', {
'fields': [
'status'
]
}),
('Critical Findings', {
'fields': [
'critical_finding', 'critical_communicated',
'critical_communicated_to', 'critical_communicated_datetime'
]
}),
('Report Dates', {
'fields': [
'dictated_datetime', 'transcribed_datetime',
'verified_datetime', 'finalized_datetime'
]
}),
('Structured Reporting', {
'fields': [
'structured_data'
],
'classes': ['collapse']
}),
('Quality and Metrics', {
'fields': [
'report_length', 'turnaround_time'
],
'classes': ['collapse']
}),
('Addenda', {
'fields': [
'addendum', 'addendum_datetime'
],
'classes': ['collapse']
}),
('Metadata', {
'fields': [
'created_at', 'updated_at'
],
'classes': ['collapse']
})
]
def study_accession(self, obj):
"""Display study accession number."""
return obj.study.accession_number
study_accession.short_description = 'Study'
def patient_name(self, obj):
"""Display patient name."""
return obj.study.patient.get_full_name()
patient_name.short_description = 'Patient'
def get_queryset(self, request):
"""Filter by user's tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
qs = qs.filter(study__tenant=request.user.tenant)
return qs.select_related('study__patient', 'radiologist')
@admin.register(ReportTemplate)
class ReportTemplateAdmin(admin.ModelAdmin):
"""
Admin interface for report templates.
"""
list_display = [
'name', 'modality', 'body_part', 'is_active',
'is_default', 'usage_count', 'created_by'
]
list_filter = [
'tenant', 'modality', 'body_part', 'is_active', 'is_default'
]
search_fields = [
'name', 'description', 'findings_template', 'impression_template'
]
readonly_fields = [
'template_id', 'usage_count', 'created_at', 'updated_at'
]
fieldsets = [
('Template Information', {
'fields': [
'template_id', 'name', 'description', 'tenant'
]
}),
('Template Scope', {
'fields': [
'modality', 'body_part'
]
}),
('Template Content', {
'fields': [
'clinical_history_template', 'technique_template',
'findings_template', 'impression_template',
'recommendations_template'
]
}),
('Structured Reporting', {
'fields': [
'structured_fields'
],
'classes': ['collapse']
}),
('Template Status', {
'fields': [
'is_active', 'is_default'
]
}),
('Usage Statistics', {
'fields': [
'usage_count'
],
'classes': ['collapse']
}),
('Metadata', {
'fields': [
'created_at', 'updated_at', 'created_by'
],
'classes': ['collapse']
})
]
def get_queryset(self, request):
"""Filter by user's tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
qs = qs.filter(tenant=request.user.tenant)
return qs.select_related('created_by')
@admin.register(ImagingOrder)
class ImagingOrderAdmin(admin.ModelAdmin):
"""
Admin interface for imaging orders.
"""
list_display = [
'order_number', 'patient_name', 'modality',
'study_description', 'priority', 'status',
'ordering_provider', 'order_datetime'
]
list_filter = [
'tenant', 'modality', 'priority', 'status',
'contrast_required', 'order_datetime'
]
search_fields = [
'order_number', 'patient__first_name', 'patient__last_name',
'patient__mrn', 'study_description', 'clinical_indication'
]
readonly_fields = [
'order_id', 'order_number', 'created_at', 'updated_at'
]
fieldsets = [
('Order Information', {
'fields': [
'order_id', 'order_number', 'tenant'
]
}),
('Patient and Provider', {
'fields': [
'patient', 'ordering_provider'
]
}),
('Order Details', {
'fields': [
'order_datetime', 'priority'
]
}),
('Imaging Details', {
'fields': [
'modality', 'study_description', 'body_part'
]
}),
('Clinical Information', {
'fields': [
'clinical_indication', 'clinical_history', 'diagnosis_code'
]
}),
('Contrast Information', {
'fields': [
'contrast_required', 'contrast_type', 'contrast_route'
]
}),
('Scheduling Information', {
'fields': [
'requested_datetime', 'scheduled_datetime'
]
}),
('Status', {
'fields': [
'status'
]
}),
('Related Information', {
'fields': [
'encounter'
]
}),
('Special Instructions', {
'fields': [
'special_instructions', 'patient_preparation'
],
'classes': ['collapse']
}),
('Metadata', {
'fields': [
'created_at', 'updated_at'
],
'classes': ['collapse']
})
]
date_hierarchy = 'order_datetime'
def patient_name(self, obj):
"""Display patient name."""
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def get_queryset(self, request):
"""Filter by user's tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
qs = qs.filter(tenant=request.user.tenant)
return qs.select_related('patient', 'ordering_provider')
# Customize admin site
admin.site.site_header = "Hospital Management System - Radiology"
admin.site.site_title = "Radiology Admin"
admin.site.index_title = "Radiology Administration"