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

Feature/sckan-279 - Admin interface changes for region + layer #255

Merged
merged 6 commits into from
Apr 5, 2024
Merged
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
46 changes: 32 additions & 14 deletions backend/composer/admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from typing import Any
from django.db.models.query import QuerySet
from django.http import HttpRequest
import nested_admin
from adminsortable2.admin import SortableAdminBase, SortableStackedInline
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from fsm_admin.mixins import FSMTransitionMixin
from django import forms

from composer.models import (
Phenotype,
Expand Down Expand Up @@ -38,6 +42,10 @@ class ProvenanceInline(admin.StackedInline):
model = Provenance
extra = 1

class SynonymeInline(admin.StackedInline):
model = Synonym
extra = 1


class ProvenanceNestedInline(nested_admin.NestedStackedInline):
model = Provenance
Expand Down Expand Up @@ -89,26 +97,32 @@ class SentenceAdmin(
NoteSentenceInline,
)


class SynonymInline(admin.TabularInline):
model = Synonym
extra = 1


class AnatomicalEntityAdmin(admin.ModelAdmin):
search_fields = ('simple_entity__name', 'region_layer__layer__name', 'region_layer__region__name')
autocomplete_fields = ('simple_entity', 'region_layer')
list_display = ('simple_entity', 'region_layer', "synonyms")
list_display_links = ('simple_entity', 'region_layer')
inlines = (SynonymeInline,)

def get_model_perms(self, request):
"""
Return empty dict to hide the model from admin index.
"""
return {}
# we need to make efficient queries to the database to get the list of anatomical entities
def get_queryset(self, request: HttpRequest) -> QuerySet[Any]:
return super().get_queryset(request) \
.select_related('simple_entity', 'region_layer__layer', 'region_layer__region') \
.prefetch_related('synonyms')

@admin.display(description="Synonyms")
def synonyms(self, obj):
synonyms = obj.synonyms.all()
return ', '.join([synonym.name for synonym in synonyms])


class AnatomicalEntityMetaAdmin(admin.ModelAdmin):
list_display = ("name", "ontology_uri")
list_display_links = ("name", "ontology_uri")
search_fields = ("name",)
search_fields = ("name", "ontology_uri")

def get_model_perms(self, request):
zsinnema marked this conversation as resolved.
Show resolved Hide resolved
return {}


class LayerAdmin(admin.ModelAdmin):
Expand All @@ -122,11 +136,15 @@ class RegionAdmin(admin.ModelAdmin):
filter_horizontal = ('layers',)


class AnatomicalEntityIntersectionAdmin(admin.ModelAdmin):
list_display = ('layer', 'region',)
class AnatomicalEntityIntersectionAdmin(nested_admin.NestedModelAdmin, admin.ModelAdmin):
list_display = ('layer', 'region')
search_fields = ("region__name", "layer__name")
list_filter = ('layer', 'region',)
raw_id_fields = ('layer', 'region',)

def get_model_perms(self, request):
return {}
zsinnema marked this conversation as resolved.
Show resolved Hide resolved


class ViaInline(SortableStackedInline):
model = Via
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.1.4 on 2024-04-03 13:57

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("composer", "0050_alter_anatomicalentityintersection_options_and_more"),
]

operations = [
migrations.AlterField(
model_name="anatomicalentity",
name="region_layer",
field=models.OneToOneField(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="composer.anatomicalentityintersection",
),
),
]
22 changes: 16 additions & 6 deletions backend/composer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,26 +254,36 @@ class Meta:
verbose_name = "Region/Layer Combination"
verbose_name_plural = "Region/Layer Combinations"

def __str__(self):
return f'{self.region.name} - {self.layer.name}'


class AnatomicalEntity(models.Model):
simple_entity = models.OneToOneField(AnatomicalEntityMeta, on_delete=models.CASCADE, null=True, blank=True)
region_layer = models.ForeignKey(AnatomicalEntityIntersection, on_delete=models.CASCADE, null=True, blank=True)
region_layer = models.OneToOneField(AnatomicalEntityIntersection, on_delete=models.CASCADE, null=True, blank=True)

@property
def name(self):
return self.simple_entity.name if self.simple_entity \
else f'{self.region_layer.region.name},{self.region_layer.layer.name}'
if self.simple_entity:
return self.simple_entity.name
elif self.region_layer:
return f'{self.region_layer.region.name},{self.region_layer.layer.name}'
return 'Unknown Anatomical Entity'

@property
def ontology_uri(self):
return self.simple_entity.ontology_uri if self.simple_entity \
else f'{self.region_layer.region.ontology_uri},{self.region_layer.layer.ontology_uri}'

if self.simple_entity:
return self.simple_entity.ontology_uri
elif self.region_layer:
return f'{self.region_layer.region.ontology_uri},{self.region_layer.layer.ontology_uri}'
return 'Unknown URI'

def __str__(self):
return self.name

class Meta:
verbose_name = "Anatomical Entity"
verbose_name_plural = "Anatomical Entities"
constraints = [
CheckConstraint(
check=(
Expand Down
16 changes: 7 additions & 9 deletions backend/composer/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from django_fsm.signals import post_transition

from .enums import CSState, NoteType
from .models import ConnectivityStatement, ExportBatch, Note, Sentence, AnatomicalEntity, AnatomicalEntityIntersection, \
AnatomicalEntityMeta
from .models import ConnectivityStatement, ExportBatch, Note, Sentence, Synonym, \
AnatomicalEntity, Layer, Region
from .services.export_services import compute_metrics, ConnectivityStatementStateService


Expand Down Expand Up @@ -48,14 +48,12 @@ def post_transition_cs(sender, instance, name, source, target, **kwargs):
# add important tag to CS when transition to COMPOSE_NOW from NPO Approved or Exported
instance = ConnectivityStatementStateService.add_important_tag(instance)


@receiver(post_save, sender=AnatomicalEntityIntersection)
def create_region_layer_anatomical_entity(sender, instance=None, created=False, **kwargs):
@receiver(post_save, sender=Layer)
def create_layer_anatomical_entity(sender, instance=None, created=False, **kwargs):
if created and instance:
AnatomicalEntity.objects.create(region_layer=instance)

AnatomicalEntity.objects.create(simple_entity=instance)

@receiver(post_save, sender=AnatomicalEntityMeta)
def create_simple_anatomical_entity(sender, instance=None, created=False, **kwargs):
@receiver(post_save, sender=Region)
def create_region_anatomical_entity(sender, instance=None, created=False, **kwargs):
if created and instance:
AnatomicalEntity.objects.create(simple_entity=instance)