Skip to content

Commit

Permalink
Adds autcomplete to ontology term lookups. Need to do the same for
Browse files Browse the repository at this point in the history
taxons, dbxrefs. Use JS in annotation_add.html to see how to use the
autocomplete. Closes #64 and closes #41, partial work for #49
  • Loading branch information
elserj committed Oct 25, 2023
1 parent a44001c commit b80eac3
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 3 deletions.
24 changes: 23 additions & 1 deletion annotations/forms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django import forms

# models import
from .models import Annotation, AnnotationDocument, AnnotationApproval
from .models import Annotation, AnnotationDocument, AnnotationApproval, AnnotationOntologyTerm
from taxon.models import Taxon


Expand All @@ -14,6 +14,8 @@ class Meta:


class AnnotationAddForm(forms.ModelForm):
ontology_term = forms.CharField(widget=forms.TextInput)
onto_pk = forms.IntegerField(widget=forms.HiddenInput)
class Meta:
model = AnnotationApproval
exclude = ['datetime', 'action', 'status', 'requestor', 'internal_gene', 'source_annotation', 'assigned_by', 'date']
Expand All @@ -22,15 +24,35 @@ class Meta:
taxon = forms.ModelChoiceField(
queryset=Taxon.objects.order_by('name').filter(rank__contains='species'))

def clean(self):
cleaned_data = super().clean()
# Need to get the ontology term pk from the hidden field in the form filled in by the autocomplete
onto_pk = cleaned_data.get('onto_pk')
if onto_pk:
ontology_term = AnnotationOntologyTerm.objects.get(pk=onto_pk)
self.cleaned_data['ontology_term']=ontology_term
return self.cleaned_data


class AnnotationAddByGeneForm(forms.ModelForm):
ontology_term = forms.CharField(widget=forms.TextInput())
onto_pk = forms.IntegerField(widget=forms.HiddenInput)
class Meta:
model = AnnotationApproval
exclude = ['datetime', 'action', 'status', 'requestor', 'internal_gene', 'source_annotation', 'assigned_by', 'date']

taxon = forms.ModelChoiceField(
queryset=Taxon.objects.order_by('name').filter(rank__contains='species'))

def clean(self):
cleaned_data = super().clean()
# Need to get the ontology term pk from the hidden field in the form filled in by the autocomplete
onto_pk = cleaned_data.get('onto_pk')
if onto_pk:
ontology_term = AnnotationOntologyTerm.objects.get(pk=onto_pk)
self.cleaned_data['ontology_term']=ontology_term
return self.cleaned_data

def __init__(self, *args, **kwargs):
db_obj_id = kwargs.pop('db_obj_id', None)
taxon = kwargs.pop('taxon', None)
Expand Down
18 changes: 18 additions & 0 deletions annotations/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django_elasticsearch_dsl_drf.serializers import DocumentSerializer

from annotations import documents as annotations_documents


class OntologyTermDocumentSerializer(DocumentSerializer):
class Meta:
document = annotations_documents.OntologyTermDocument
fields = (
'id',
'onto_term',
'term_name',
'term_definition',
'term_synonyms',
'term_is_obsolete',
'aspect',
)

50 changes: 50 additions & 0 deletions annotations/templates/annotations/annotation_add.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,63 @@

{% block title %}Add individual Annotation{% endblock title %}

{% block extra_js %}
<script>
$(function() {
$("#id_ontology_term").autocomplete({
source: function (request, response) {
$.ajax({
url: "{% url 'annotations:autocomplete' %}",
dataType: "json",
data: {
q: request.term
},
success: function(data) {
response($.map(data, function (item) {
return {
label: item.term_name + " - " + item.onto_term,
value: item.id,
aspect: item.aspect,
};
}));
}
})
},
minLength: 3,
open: function() {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function() {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
},
select: function(event, ui) {
event.preventDefault();
$(this).val(ui.item.label);
$("#hidden-auto").val(ui.item.value);
$("#id_aspect").val(ui.item.aspect);
//document.querySelector("label[for='id_aspect']").textContent = "Aspect (already selected by ontology term)";
},
focus: function(event, ui) {
event.preventDefault();
$(this).val(ui.item.label);
$("#hidden-auto").val(ui.item.value);
$("#id_aspect").val(ui.item.aspect);
//document.querySelector("label[for='id_aspect']").textContent = "Aspect (already selected by ontology term)";
}
})
});
</script>

{% endblock %}

{% block main %}
{% if logged_in and superuser %}
Use this page to add a single annotation
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Submit" class="btn btn-primary">
<input id="hidden-auto" name="onto_pk" type="hidden">
</form>
{% else %}
<h2>You must be a logged in superuser to use this import page</h2>
Expand Down
1 change: 1 addition & 0 deletions annotations/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
path('by-reference/<slug:id>', views.SearchByReferenceView.as_view(), name='by-reference'),
path('by-taxon/<int:id>', views.SearchByTaxonView.as_view(), name='by-taxon'),
path('ontology_update/', views.OntologyUpdateView.as_view(), name='ontology-update'),
path('autocomplete/', views.OntologyTermAPIView.as_view(), name='autocomplete'),
path('', views.BaseAnnotationView.as_view(), name='base_annotation')

] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
32 changes: 30 additions & 2 deletions annotations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.utils import timezone

from django.db.models import Q
from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponseRedirect, HttpResponse, JsonResponse
from django.shortcuts import render, get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import TemplateView, FormView, ListView
Expand All @@ -24,8 +24,14 @@

# ElasticSearch import
from .documents import AnnotationDocument as ESAnnotationDocument
from .documents import OntologyTermDocument as ESOntologyTermDocument
from genes.documents import GeneDocument as ESGeneDocument
from django_elasticsearch_dsl.search import Search

from .serializers import OntologyTermDocumentSerializer

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer

# choices import
import curate.choices as choices
Expand Down Expand Up @@ -766,6 +772,28 @@ def get_queryset(self):
return result


class OntologyTermAPIView(APIView):
document_class = ESOntologyTermDocument
renderer_classes = [JSONRenderer]

def get(self, request, *args, **kwargs):
max_items = 5
q = request.GET.get('q')

if q:
if ':' in q:
q = q.replace(':', '\":\"')
search_term = "*" + q + "*"
# Use the boosts (^10) to order the results
terms = ESOntologyTermDocument.search().extra(size=max_items).query("multi_match", query=search_term,
fields=["onto_term^10", "term_name^5", "term_definition^3", "term_synonyms"])
#Convert to JSON
serializers = OntologyTermDocumentSerializer(terms, many=True)
return Response(serializers.data)
else:
return Response(None)


def adjust_pagination(context):
adjacent_pages = 2
page_number = context['page_obj'].number
Expand Down
1 change: 1 addition & 0 deletions curate/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
'django.contrib.humanize',

'django_elasticsearch_dsl',
'django_elasticsearch_dsl_drf',

'mozilla_django_oidc',

Expand Down
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ services:
- "3307:3306"
env_file:
- .env
command: [
'--wait_timeout=28800',
]
volumes:
- /docker/curate/mysqldata:/var/lib/mysql
- /docker/curate/mysqld:/var/run/mysql
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ django-timezone-field==4.2.1
djangorestframework==3.12.4
elasticsearch-dsl>=7.0.0,<8.0.0
django-elasticsearch-dsl
django-elasticsearch-dsl-drf
idna==3.2
importlib-metadata==4.8.1
kombu==5.1.0
Expand Down

0 comments on commit b80eac3

Please sign in to comment.