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")