Add caching and group detection for series images in series viewer
This commit is contained in:
+66
-5
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user