Files
penracourses/atlas/filters.py
T

417 lines
13 KiB
Python
Executable File

import django_filters
from .models import (
Case,
CaseCollection,
Condition,
Finding,
PathologicalProcess,
Presentation,
QuestionSchema,
Series,
Structure,
Subspecialty,
NormalCase,
Resource,
Site,
)
from django.contrib.auth.models import User
from django.db.models import Q
def get_authors(request):
if request is None:
return User.objects.none()
if not request.user.groups.filter(name="atlas_editor").exists():
queryset = User.objects.filter(id=request.user.id)
else:
queryset = User.objects.all()
return queryset
def get_cases(request):
if request is None:
return Case.objects.none()
if not request.user.groups.filter(name="atlas_editor").exists():
queryset = Case.objects.filter(author__id=request.user.id)
else:
queryset = Case.objects.all()
return queryset
def get_series(request):
if request is None:
return Series.objects.none()
if not request.user.groups.filter(name="atlas_editor").exists():
queryset = Series.objects.filter(author__id=request.user.id)
else:
queryset = Series.objects.all()
queryset = queryset.prefetch_related("examination", "plane")
return queryset
class CaseCollectionFilter(django_filters.FilterSet):
author = django_filters.ModelMultipleChoiceFilter(
queryset=get_authors, null_label="No author"
)
cases = django_filters.ModelMultipleChoiceFilter(
queryset=get_cases, null_label="No cases"
)
class Meta:
model = CaseCollection
fields = (
"archive",
"author",
) # "site",
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
if not request.user.groups.filter(name="atlas_editor").exists():
queryset = queryset.prefetch_related("author").filter(
author__id=request.user.id
)
super(CaseCollectionFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
class CaseFilter(django_filters.FilterSet):
author = django_filters.ModelMultipleChoiceFilter(
queryset=get_authors, null_label="No author"
)
series = django_filters.ModelMultipleChoiceFilter(
queryset=get_series, null_label="No series"
)
differential_case = django_filters.ModelMultipleChoiceFilter(
label="Differential",
field_name="differentialcase__condition",
# to_field_name="differential",
queryset=Condition.objects.all(),
)
class Meta:
model = Case
fields = (
"created_date",
"open_access",
"author",
"differential_case",
) # "site",
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
if not request.user.groups.filter(name="atlas_editor").exists():
queryset = queryset.prefetch_related("author").filter(
(Q(author__id=request.user.id) | Q(open_access=True))
)
super(CaseFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
class SeriesFilter(django_filters.FilterSet):
case = django_filters.ModelMultipleChoiceFilter(
queryset=get_cases, null_label="No case"
)
author = django_filters.ModelMultipleChoiceFilter(
queryset=get_authors, null_label="No author"
)
class Meta:
model = Series
fields = ("modality", "case", "examination", "author")
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
if not request.user.groups.filter(name="atlas_editor").exists():
# queryset = queryset.filter(open_access=True) | queryset.filter(author__id=request.user.id)
queryset = queryset.filter(author__id=request.user.id)
super(SeriesFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
class ConditionFilter(django_filters.FilterSet):
# Replace legacy `primary` filter with `is_canonical` and provide a
# `synonym` filter which will filter by the canonical group of the
# selected condition.
is_canonical = django_filters.BooleanFilter(method="filter_is_canonical", label="Canonical")
synonym = django_filters.ModelChoiceFilter(queryset=Condition.objects.all(), method="filter_synonym", label="Synonym group")
class Meta:
model = Condition
fields = {
"name": ["icontains"],
"subspecialty": ["exact"],
"rcr_curriculum": ["exact"],
}
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
super(ConditionFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
def filter_is_canonical(self, queryset, name, value):
if value in (True, "True", "true", 1, "1"):
return queryset.filter(canonical__isnull=True)
if value in (False, "False", "false", 0, "0"):
return queryset.filter(canonical__isnull=False)
return queryset
def filter_synonym(self, queryset, name, value):
# value is a Condition instance selected in the filter. Return all
# Conditions that belong to the same canonical group as `value`.
if not value:
return queryset
master = value.canonical if value.canonical else value
return queryset.filter(Q(canonical=master) | Q(pk=master.pk))
class FindingFilter(django_filters.FilterSet):
# Replace legacy `primary`/`synonym` with canonical-based filters
is_canonical = django_filters.BooleanFilter(method="filter_is_canonical", label="Canonical")
synonym = django_filters.ModelChoiceFilter(queryset=Finding.objects.all(), method="filter_synonym", label="Synonym group")
class Meta:
model = Finding
fields = {
"name": ["icontains"],
}
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
super(FindingFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
def filter_is_canonical(self, queryset, name, value):
if value in (True, "True", "true", 1, "1"):
return queryset.filter(canonical__isnull=True)
if value in (False, "False", "false", 0, "0"):
return queryset.filter(canonical__isnull=False)
return queryset
def filter_synonym(self, queryset, name, value):
# value is a Finding instance selected in the filter. Return all
# Findings that belong to the same canonical group as `value`.
if not value:
return queryset
master = value.canonical if value.canonical else value
return queryset.filter(Q(canonical=master) | Q(pk=master.pk))
class StructureFilter(django_filters.FilterSet):
is_canonical = django_filters.BooleanFilter(method="filter_is_canonical", label="Canonical")
synonym = django_filters.ModelChoiceFilter(queryset=Structure.objects.all(), method="filter_synonym", label="Synonym group")
class Meta:
model = Structure
fields = {"name": ["icontains"]}
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
super(StructureFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
def filter_is_canonical(self, queryset, name, value):
if value in (True, "True", "true", 1, "1"):
return queryset.filter(canonical__isnull=True)
if value in (False, "False", "false", 0, "0"):
return queryset.filter(canonical__isnull=False)
return queryset
def filter_synonym(self, queryset, name, value):
if not value:
return queryset
master = value.canonical if value.canonical else value
return queryset.filter(Q(canonical=master) | Q(pk=master.pk))
class PresentationFilter(django_filters.FilterSet):
class Meta:
model = Presentation
fields = ("name", "subspecialty")
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
super(PresentationFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
class PathologicalProcessFilter(django_filters.FilterSet):
class Meta:
model = PathologicalProcess
fields = ("name",)
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
super(PathologicalProcessFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
class SubspecialtyFilter(django_filters.FilterSet):
class Meta:
model = Subspecialty
fields = ("name",)
def __init__(
self,
data=None,
queryset=None,
prefix=None,
strict=None,
user=None,
request=None,
):
super(SubspecialtyFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
)
pass
class NormalCaseFilter(django_filters.FilterSet):
"""FilterSet for the NormalCase model allowing filtering by
examination, modality and nearest-year age ranges.
"""
examination = django_filters.ModelChoiceFilter(queryset=Series.objects.none())
modality = django_filters.ModelChoiceFilter(queryset=Series.objects.none())
# Accept min/max as years in the UI but filter against the canonical
# `age_days` field by converting years -> days.
min_age = django_filters.NumberFilter(label="Min age", method="filter_min_age")
max_age = django_filters.NumberFilter(label="Max age", method="filter_max_age")
class Meta:
model = NormalCase
fields = ("examination", "modality", "age_days")
def __init__(self, data=None, queryset=None, prefix=None, strict=None, user=None, request=None):
# Use the global Examination and Modality querysets from the Series model
from generic.models import Examination, Modality
# Set up the actual querysets for the filters
self.base_filters.get("examination").queryset = Examination.objects.all()
self.base_filters.get("modality").queryset = Modality.objects.all()
# If not an atlas editor restrict to cases authored by the user or open access cases
if request is not None and not request.user.groups.filter(name="atlas_editor").exists():
from django.db.models import Q
if queryset is None:
queryset = NormalCase.objects.select_related("case")
queryset = queryset.filter((Q(case__author__id=request.user.id) | Q(case__open_access=True)))
super(NormalCaseFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request)
def filter_min_age(self, queryset, name, value):
try:
days = int(float(value) * 365.25)
except Exception:
return queryset
return queryset.filter(age_days__gte=days)
def filter_max_age(self, queryset, name, value):
try:
days = int(float(value) * 365.25)
except Exception:
return queryset
return queryset.filter(age_days__lte=days)
class ResourceFilter(django_filters.FilterSet):
name = django_filters.CharFilter(field_name='name', lookup_expr='icontains')
site = django_filters.ModelMultipleChoiceFilter(field_name='sites', queryset=lambda request: Site.objects.all() if True else Site.objects.none())
subspecialty = django_filters.ModelMultipleChoiceFilter(field_name='subspecialty', queryset=Subspecialty.objects.all())
author = django_filters.ModelMultipleChoiceFilter(queryset=get_authors, null_label='No author')
has_file = django_filters.BooleanFilter(method='filter_has_file', label='Has file')
class Meta:
model = Resource
fields = ('name', 'site', 'subspecialty', 'author')
def filter_has_file(self, queryset, name, value):
if value is True:
return queryset.exclude(file__isnull=True).exclude(file__exact='')
elif value is False:
return queryset.filter(file__isnull=True) | queryset.filter(file__exact='')
return queryset
class QuestionSchemaFilter(django_filters.FilterSet):
class Meta:
model = QuestionSchema
fields = ("name", "description")