Skip to content

Commit

Permalink
Merge pull request #807 from cortex-lab/removeProjectField
Browse files Browse the repository at this point in the history
Remove project field
  • Loading branch information
k1o0 authored Mar 15, 2024
2 parents dbde246 + 65b4a2a commit 07833ed
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 21 deletions.
39 changes: 39 additions & 0 deletions alyx/actions/migrations/0022_project_to_projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 4.2.10 on 2024-03-14 14:28
import logging

from django.db import migrations
from django.db.models import F, Q

logger = logging.getLogger(__name__)

def project2projects(apps, schema_editor):
"""
Find sessions where the project field (singular) value is not in the projects (plural) many-to-many
field and updates them.
Tested on local instance.
"""
Session = apps.get_model('actions', 'Session')
sessions = Session.objects.exclude(Q(project__isnull=True) | Q(projects=F('project')))

# Check query worked
# from one.util import ensure_list
# for session in sessions.values('pk', 'project', 'projects'):
# assert session['project'] not in ensure_list(session['projects'])

for session in sessions:
session.projects.add(session.project)
# session.project = None
# session.save() # No need to save

assert Session.objects.exclude(Q(project__isnull=True) | Q(projects=F('project'))).count() == 0
logger.info(f'project -> projects: {sessions.count():,g} sessions updated')


class Migration(migrations.Migration):

dependencies = [
('actions', '0021_alter_session_extended_qc'),
]

operations = [migrations.RunPython(project2projects)]
17 changes: 17 additions & 0 deletions alyx/actions/migrations/0023_remove_session_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.10 on 2024-03-14 14:54

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('actions', '0022_project_to_projects'),
]

operations = [
migrations.RemoveField(
model_name='session',
name='project',
),
]
13 changes: 6 additions & 7 deletions alyx/actions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,6 @@ class Session(BaseAction):
parent_session = models.ForeignKey('Session', null=True, blank=True,
on_delete=models.SET_NULL,
help_text="Hierarchical parent to this session")
project = models.ForeignKey('subjects.Project', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='Session Project',
related_name='oldproject')
projects = models.ManyToManyField('subjects.Project', blank=True,
verbose_name='Session Projects')
type = models.CharField(max_length=255, null=True, blank=True,
Expand All @@ -267,12 +264,14 @@ class Session(BaseAction):
verbose_name='last updated')

def save(self, *args, **kwargs):
# Default project is the subject's project.
if not self.project_id:
self.project = self.subject.projects.first()
# Default project is the subject's projects.
if not self.lab:
self.lab = self.subject.lab
return super(Session, self).save(*args, **kwargs)
obj = super(Session, self).save(*args, **kwargs)
if self.projects.count() == 0 and self.subject.projects.count() > 0:
from subjects.models import Project
self.projects.add(*Project.objects.filter(subject=self.subject))
return obj

def __str__(self):
try:
Expand Down
10 changes: 5 additions & 5 deletions alyx/actions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ class SessionAPIList(generics.ListCreateAPIView):
- **lab**: lab name (exact)
- **task_protocol** (icontains)
- **location**: location name (icontains)
- **project**: project name (icontains)
- **projects**: project name (icontains)
- **json**: queries on json fields, for example here `tutu`
- exact/equal lookup: `/sessions?extended_qc=tutu,True`,
- gte lookup: `/sessions/?extended_qc=tutu__gte,0.5`,
Expand All @@ -369,10 +369,10 @@ class SessionAPIList(generics.ListCreateAPIView):
- **histology**: returns sessions for which the subject has an histology session:
`/sessions?histology=True`
- **django**: generic filter allowing lookups (same syntax as json filter)
`/sessions?django=project__name__icontains,matlab`
filters sessions that have matlab in the project name
`/sessions?django=~project__name__icontains,matlab`
does the exclusive set: filters sessions that do not have matlab in the project name
`/sessions?django=projects__name__icontains,matlab`
filters sessions that have matlab in the project names
`/sessions?django=~projects__name__icontains,matlab`
does the exclusive set: filters sessions that do not have matlab in the project names
[===> session model reference](/admin/doc/models/actions.session)
"""
Expand Down
4 changes: 2 additions & 2 deletions alyx/experiments/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class ProbeInsertionFilter(BaseFilterSet):
datasets = CharFilter(field_name='datasets', method='filter_datasets')
dataset_qc_lte = CharFilter(field_name='dataset_qc', method='filter_dataset_qc_lte')
lab = CharFilter(field_name='session__lab__name', lookup_expr='iexact')
project = CharFilter(field_name='session__project__name', lookup_expr='icontains')
project = CharFilter(field_name='session__projects__name', lookup_expr='icontains')
task_protocol = CharFilter(field_name='session__task_protocol', lookup_expr='icontains')
tag = CharFilter(field_name='tag', method='filter_tag')
# brain region filters
Expand Down Expand Up @@ -436,7 +436,7 @@ class FOVList(generics.ListCreateAPIView):
`/fields-of-view?provenance=Estimate`
- **atlas**: One or more brain regions covered by a field of view
- **subject**: subject nickname: `/fields-of-view?subject=Algernon`
- **project**: the
- **project**: the project name
- **date**: session date: `/fields-of-view?date=2020-01-15`
- **experiment_number**: session number `/fields-of-view?experiment_number=1`
- **session**: `/fields-of-view?session=aad23144-0e52-4eac-80c5-c4ee2decb198`
Expand Down
11 changes: 4 additions & 7 deletions scripts/sync_ucl/prune_cortexlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,13 @@
json_file_out = '../scripts/sync_ucl/cortexlab_pruned.json'


# Since we currently still use both the project and the projects field, we need to filter for
# either containing an IBL project
ibl_proj = (Q(project__name__icontains='ibl') | Q(projects__name__icontains='ibl') |
Q(project__name='practice') | Q(projects__name='practice'))
# Filter for sessions containing an IBL project
ibl_proj = Q(projects__name__icontains='ibl') | Q(projects__name='practice')
ses = Session.objects.using('cortexlab').filter(ibl_proj)
# remove all subjects that never had anything to do with IBL
sub_ibl = list(ses.values_list('subject', flat=True))
sub_ibl += list(Subject.objects.values_list('pk', flat=True))
sub_ibl += list(Subject.objects.using('cortexlab').filter(
projects__name__icontains='ibl').values_list('pk', flat=True))
sub_ibl += list(Subject.objects.using('cortexlab').filter(ibl_proj).values_list('pk', flat=True))
Subject.objects.using('cortexlab').exclude(pk__in=sub_ibl).delete()

# then remove base Sessions
Expand Down Expand Up @@ -76,7 +73,7 @@


# import projects from cortexlab. remove those that don't correspond to any session
pk_projs = list(filter(None, flatten(ses_ucl.values_list('project', 'projects').distinct())))
pk_projs = list(filter(None, flatten(ses_ucl.values_list('projects').distinct())))
pk_projs += list(Project.objects.values_list('pk', flat=True))

Project.objects.using('cortexlab').exclude(pk__in=pk_projs).delete()
Expand Down

0 comments on commit 07833ed

Please sign in to comment.