Add caching and group detection for series images in series viewer

This commit is contained in:
Ross
2026-05-21 22:24:44 +01:00
parent f85aefe5c7
commit 734460777b
3 changed files with 103 additions and 10 deletions
+66 -5
View File
@@ -10,6 +10,8 @@ from rad.settings import REMOTE_URL
from django.db.models.fields.files import ImageField
from django.db.models.fields.related import ForeignKey
from django.db import models
from django.db.models.signals import pre_save, post_save, post_delete
from django.dispatch import receiver
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.core.cache import cache
@@ -129,11 +131,34 @@ def _normalise_group_rule_value(value):
return text
def _series_declared_groups_cache_key(series_id):
return f"atlas:series_declared_groups:{series_id}"
def invalidate_series_declared_groups_cache(series_id):
if not series_id:
return
cache.delete(_series_declared_groups_cache_key(series_id))
def _build_declared_series_groups(series, series_images_with_urls):
cache_key = f"atlas:series_declared_groups:{series.pk}:{int(series.modified_date.timestamp())}:{len(series_images_with_urls)}"
cache_key = _series_declared_groups_cache_key(series.pk)
signature = {
"series_modified": int(series.modified_date.timestamp()) if getattr(series, "modified_date", None) else 0,
"image_count": len(series_images_with_urls),
"images": [
{
"pk": getattr(image_obj, "pk", None),
"position": getattr(image_obj, "position", None),
"url": image_url,
}
for image_obj, image_url in series_images_with_urls
],
}
cached = cache.get(cache_key)
if cached is not None:
return cached
if isinstance(cached, dict):
if cached.get("signature") == signature:
return cached.get("groups", [])
rules = [
"dwiBValue",
@@ -232,7 +257,7 @@ def _build_declared_series_groups(series, series_images_with_urls):
"groupValues": {},
}
]
cache.set(cache_key, result, timeout=60 * 60)
cache.set(cache_key, {"signature": signature, "groups": result}, timeout=60 * 60)
return result
grouped = {}
@@ -288,7 +313,7 @@ def _build_declared_series_groups(series, series_images_with_urls):
}
)
cache.set(cache_key, ordered_groups, timeout=60 * 60)
cache.set(cache_key, {"signature": signature, "groups": ordered_groups}, timeout=60 * 60)
return ordered_groups
@@ -1274,6 +1299,42 @@ class SeriesImage(SeriesImageBase):
# }}
@receiver(pre_save, sender=SeriesImage)
def _capture_previous_series_for_series_image(sender, instance, **kwargs):
if not getattr(instance, "pk", None):
instance._previous_series_id_for_cache = None
return
previous_series_id = (
sender.objects.filter(pk=instance.pk).values_list("series_id", flat=True).first()
)
instance._previous_series_id_for_cache = previous_series_id
def _invalidate_and_touch_series(series_id):
if not series_id:
return
invalidate_series_declared_groups_cache(series_id)
Series.objects.filter(pk=series_id).update(modified_date=timezone.now())
@receiver(post_save, sender=SeriesImage)
def _invalidate_declared_groups_on_series_image_save(sender, instance, **kwargs):
affected_series_ids = set()
if instance.series_id:
affected_series_ids.add(instance.series_id)
previous_series_id = getattr(instance, "_previous_series_id_for_cache", None)
if previous_series_id:
affected_series_ids.add(previous_series_id)
for series_id in affected_series_ids:
_invalidate_and_touch_series(series_id)
@receiver(post_delete, sender=SeriesImage)
def _invalidate_declared_groups_on_series_image_delete(sender, instance, **kwargs):
_invalidate_and_touch_series(getattr(instance, "series_id", None))
class SeriesFinding(FindingBase):
series = models.ForeignKey(
"Series", related_name="findings", on_delete=models.SET_NULL, null=True