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/esckan-35 - Composer REST new generic endpoint - public - KnowledgeStatement #260

Merged
merged 6 commits into from
Apr 11, 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
7 changes: 6 additions & 1 deletion backend/composer/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class SentenceAdmin(
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 = ('simple_entity', 'region_layer', "synonyms", "ontology_uri")
list_display_links = ('simple_entity', 'region_layer')
inlines = (SynonymInline,)

Expand All @@ -114,6 +114,11 @@ def get_queryset(self, request: HttpRequest) -> QuerySet[Any]:
def synonyms(self, obj):
synonyms = obj.synonyms.all()
return ', '.join([synonym.name for synonym in synonyms])

zsinnema marked this conversation as resolved.
Show resolved Hide resolved
@admin.display(description="Ontology URI")
def ontology_uri(self, obj):
return obj.ontology_uri



class AnatomicalEntityMetaAdmin(admin.ModelAdmin):
Expand Down
62 changes: 62 additions & 0 deletions backend/composer/api/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
Via,
Specie, Destination,
)
from django_filters import rest_framework
from django_filters import CharFilter, BaseInFilter


def field_has_content(queryset, name, value):
Expand Down Expand Up @@ -95,6 +97,66 @@ class Meta:
fields = []


class ListCharFilter(BaseInFilter, CharFilter):
pass


class KnowledgeStatementFilterSet(rest_framework.FilterSet):
via_uris = ListCharFilter(method='filter_via_uris', label='Via URI')
destination_uris = ListCharFilter(method='filter_destination_uris', label='Destination URI')
origin_uris = ListCharFilter(method='filter_origin_uris', label='Origin URI')
population_uris = ListCharFilter(method='filter_population_uris', label='Reference URI')

class Meta:
model = ConnectivityStatement
fields = ['via_uris', 'destination_uris', 'origin_uris', 'population_uris']
distinct = True

@property
def qs(self):
return super().qs.distinct()

def filter_population_uris(self, queryset, name, value):
return queryset.filter(reference_uri__in=value)

def filter_via_uris(self, queryset, name, value):
via_uris = value
via_ids = Via.objects.none()
for uri in via_uris:
via_ids = via_ids.union(
Via.objects.filter(anatomical_entities__simple_entity__ontology_uri=uri).prefetch_related('anatomical_entities__simple_entity')
.union(Via.objects.filter(anatomical_entities__region_layer__layer__ontology_uri=uri).prefetch_related('anatomical_entities__region_layer__layer'))
.union(Via.objects.filter(anatomical_entities__region_layer__region__ontology_uri=uri).prefetch_related('anatomical_entities__region_layer__region'))
.values_list("id", flat=True)
)
return queryset.filter(via__in=via_ids)

def filter_destination_uris(self, queryset, name, value):
destination_uris = value
destination_ids = Destination.objects.none()
for uri in destination_uris:
destination_ids = destination_ids.union(
Destination.objects.filter(anatomical_entities__simple_entity__ontology_uri=uri).prefetch_related('anatomical_entities__simple_entity')
.union(Destination.objects.filter(anatomical_entities__region_layer__layer__ontology_uri=uri).prefetch_related('anatomical_entities__region_layer__layer'))
.union(Destination.objects.filter(anatomical_entities__region_layer__region__ontology_uri=uri).prefetch_related('anatomical_entities__region_layer__region'))
.values_list("id", flat=True)
)
return queryset.filter(destinations__in=destination_ids)

def filter_origin_uris(self, queryset, name, value):
origin_uris = value
origin_ids = AnatomicalEntity.objects.none()
for uri in origin_uris:
origin_ids = origin_ids.union(
AnatomicalEntity.objects.filter(simple_entity__ontology_uri=uri).prefetch_related('simple_entity')
.union(AnatomicalEntity.objects.filter(region_layer__layer__ontology_uri=uri).prefetch_related('region_layer__layer'))
.union(AnatomicalEntity.objects.filter(region_layer__region__ontology_uri=uri).prefetch_related('region_layer__region'))
.values_list("id", flat=True)
)
return queryset.filter(origins__in=origin_ids)



class AnatomicalEntityFilter(django_filters.FilterSet):
name = django_filters.CharFilter(method="filter_name")
exclude_ids = NumberInFilter(field_name='id', exclude=True)
Expand Down
15 changes: 15 additions & 0 deletions backend/composer/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,3 +680,18 @@ class Meta:
"errors"
)


class KnowledgeStatementSerializer(ConnectivityStatementSerializer):
"""Knowledge Statement"""
class Meta(ConnectivityStatementSerializer.Meta):
fields = (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: I think we should add the reference_uri here since that's one of the fields we allow filtering on.

"id",
"sentence_id",
"species",
"origins",
"vias",
"destinations",
"apinatomy_model",
"phenotype_id",
"phenotype",
)
2 changes: 2 additions & 0 deletions backend/composer/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
AnatomicalEntityViewSet,
PhenotypeViewSet,
ConnectivityStatementViewSet,
KnowledgeStatementViewSet,
jsonschemas,
NoteViewSet,
ProfileViewSet,
Expand Down Expand Up @@ -42,4 +43,5 @@
urlpatterns = [
path("", include(router.urls)),
path("jsonschemas/", jsonschemas, name="jsonschemas"),
path("knowledge-statement/", KnowledgeStatementViewSet.as_view(), name="knowledge-statement"),
zsinnema marked this conversation as resolved.
Show resolved Hide resolved
]
32 changes: 32 additions & 0 deletions backend/composer/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from rest_framework.renderers import INDENT_SEPARATORS
from rest_framework.response import Response
from rest_framework.serializers import ValidationError
from rest_framework import generics
from django_filters.rest_framework import DjangoFilterBackend

from composer.services.state_services import (
ConnectivityStatementStateService,
Expand All @@ -17,6 +19,7 @@
from .filtersets import (
SentenceFilter,
ConnectivityStatementFilter,
KnowledgeStatementFilterSet,
AnatomicalEntityFilter,
NoteFilter,
ViaFilter,
Expand All @@ -26,6 +29,7 @@
AnatomicalEntitySerializer,
PhenotypeSerializer,
ConnectivityStatementSerializer,
KnowledgeStatementSerializer,
NoteSerializer,
ProfileSerializer,
SentenceSerializer,
Expand Down Expand Up @@ -345,6 +349,34 @@ def partial_update(self, request, *args, **kwargs):
return super().partial_update(request, *args, **kwargs)


@extend_schema(tags=["public"])
class KnowledgeStatementViewSet(
generics.ListAPIView,
):
"""
KnowledgeStatement that only allows GET to get the list of ConnectivityStatements
"""
model = ConnectivityStatement
queryset = ConnectivityStatement.objects.exported()
serializer_class = KnowledgeStatementSerializer
permission_classes = [
permissions.AllowAny,
]
filter_backends = [DjangoFilterBackend]
filterset_class = KnowledgeStatementFilterSet

@property
def allowed_methods(self):
return ['GET']

def get_serializer_class(self):
return KnowledgeStatementSerializer


def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)


class TagViewSet(viewsets.ReadOnlyModelViewSet):
"""
Tag
Expand Down
3 changes: 3 additions & 0 deletions backend/composer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ def get_queryset(self):

def excluding_draft(self):
return self.get_queryset().exclude(state=CSState.DRAFT)

def exported(self):
return self.get_queryset().filter(state=CSState.EXPORTED)


class SentenceStatementManager(models.Manager):
Expand Down