Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/notes and narrative #897

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion alyx/actions/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
from django.conf import settings
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.db.models import Case, When
from django.db.models import Case, When, Exists, OuterRef
from django.urls import reverse
from django.utils.html import format_html
from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter
from django.contrib.admin import TabularInline
from django.contrib.contenttypes.models import ContentType
from rangefilter.filters import DateRangeFilter

from alyx.base import (BaseAdmin, DefaultListFilter, BaseInlineAdmin, get_admin_url)
Expand All @@ -20,6 +21,7 @@
)
from data.models import Dataset, FileRecord
from misc.admin import NoteInline
from misc.models import Note
from subjects.models import Subject
from .water_control import WaterControl
from experiments.models import ProbeInsertion, FOV
Expand Down Expand Up @@ -104,6 +106,53 @@ def queryset(self, request, queryset):
return queryset.all()


class HasNarrativeFilter(DefaultListFilter):
title = 'narrative'
parameter_name = 'has_narrative'

def lookups(self, request, model_admin):
return (
(None, 'All'),
('narrative', 'Has narrative'),
('no_narrative', 'No narrative'),
)

def queryset(self, request, queryset):
if self.value is not None:
regex_string = r'^(?:\s*|auto-generated session)$'
if self.value() == 'narrative':
return queryset.exclude(narrative__regex=regex_string)
if self.value() == 'no_narrative':
return queryset.filter(narrative__regex=regex_string)
else:
return queryset.all()


class HasNoteFilter(DefaultListFilter):
title = 'note'
parameter_name = 'has_note'

def lookups(self, request, model_admin):
return (
(None, 'All'),
('notes', 'Has notes'),
('no_notes', 'No notes'),
)

def queryset(self, request, queryset):
if self.value is not None:
notes_subquery = Note.objects.filter(
content_type=ContentType.objects.get_for_model(Session),
object_id=OuterRef('pk')
)
if self.value() == 'notes':
return queryset.filter(Exists(notes_subquery))
if self.value() == 'no_notes':
return queryset.exclude(Exists(notes_subquery))
else:
return queryset.all()


def _bring_to_front(ids, id):
if id in ids:
ids.remove(id)
Expand Down Expand Up @@ -496,6 +545,8 @@ class SessionAdmin(BaseActionAdmin):
('start_time', DateRangeFilter),
('projects', RelatedDropdownFilter),
('lab', RelatedDropdownFilter),
(HasNarrativeFilter),
(HasNoteFilter),
]
search_fields = ('subject__nickname', 'lab__name', 'projects__name', 'users__username',
'task_protocol', 'pk')
Expand Down
1 change: 1 addition & 0 deletions alyx/alyx/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ def alyx_mail(to, subject, text=''):
'Water restrictions',
'Weighings',
'Subject requests',
'Notes',
]),
('Data files',
['Data repository types',
Expand Down
27 changes: 27 additions & 0 deletions alyx/misc/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from django.contrib.postgres.fields import JSONField
from django.utils.html import format_html, format_html_join
from django.utils.safestring import mark_safe
from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter
from rest_framework.authtoken.models import TokenProxy
from rangefilter.filters import DateRangeFilter

from misc.models import Note, Lab, LabMembership, LabLocation, CageType, \
Enrichment, Food, Housing, HousingSubject
Expand Down Expand Up @@ -105,9 +107,34 @@ def formfield_for_dbfield(self, db_field, **kwargs):
return super(ImageWidgetAdmin, self).formfield_for_dbfield(db_field, **kwargs)


class HasImageFilter(DefaultListFilter):
title = 'image'
parameter_name = 'has_image'

def lookups(self, request, model_admin):
return (
(None, 'All'),
('image', 'Has image'),
('no_image', 'No image'),
)

def queryset(self, request, queryset):
if self.value() == 'image':
return queryset.exclude(image__exact='')
if self.value() == 'no_image':
return queryset.filter(image__exact='')
elif self.value is None:
return queryset.all()


class NoteAdmin(ImageWidgetAdmin):
list_display = ['user', 'date_time', 'content_object', 'text', 'image']
list_display_links = ['date_time']
list_filter = [('user', RelatedDropdownFilter),
('date_time', DateRangeFilter),
('content_type', RelatedDropdownFilter),
(HasImageFilter),
]
image_fields = ['image']
fields = ['user', 'date_time', 'text', 'image', 'content_type', 'object_id']
ordering = ('-date_time',)
Expand Down