mirror of
https://github.com/Southampton-RSG/breccia-mapper.git
synced 2026-03-03 03:17:07 +00:00
feat(people): Add network view
Network view shows people and relationships between them Resolves #21 Resolves #20 Part of #14
This commit is contained in:
@@ -71,6 +71,7 @@ THIRD_PARTY_APPS = [
|
|||||||
'dbbackup',
|
'dbbackup',
|
||||||
'django_countries',
|
'django_countries',
|
||||||
'django_select2',
|
'django_select2',
|
||||||
|
'rest_framework',
|
||||||
]
|
]
|
||||||
|
|
||||||
FIRST_PARTY_APPS = [
|
FIRST_PARTY_APPS = [
|
||||||
|
|||||||
26
people/serializers.py
Normal file
26
people/serializers.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"""
|
||||||
|
Serialize models to and deserialize from JSON.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
class PersonSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.Person
|
||||||
|
fields = [
|
||||||
|
'pk',
|
||||||
|
'name',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class RelationshipSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.Relationship
|
||||||
|
fields = [
|
||||||
|
'pk',
|
||||||
|
'source',
|
||||||
|
'target',
|
||||||
|
]
|
||||||
120
people/templates/people/network.html
Normal file
120
people/templates/people/network.html
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">Network</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id="cy"
|
||||||
|
style="width: 100%; min-height: 1000px; flex-grow: 1; border: 2px solid black"></div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_script %}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.14.0/cytoscape.min.js"
|
||||||
|
integrity="sha256-rI7zH7xDqO306nxvXUw9gqkeBpvvmddDdlXJjJM7rEM="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
var cy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all :class:`Person` records from people:person.api.list endpoint.
|
||||||
|
*
|
||||||
|
* @returns JQuery Promise from AJAX
|
||||||
|
*/
|
||||||
|
function get_people_ajax(){
|
||||||
|
return $.ajax({
|
||||||
|
url: '{% url "people:person.api.list" %}',
|
||||||
|
success: success_people_ajax,
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add nodes to Cytoscape network from :class:`Person` JSON.
|
||||||
|
*
|
||||||
|
* @param data: JSON representation of people
|
||||||
|
* @param status: unused
|
||||||
|
* @param xhr: unused
|
||||||
|
*/
|
||||||
|
function success_people_ajax(data, status, xhr) {
|
||||||
|
for (var person of data) {
|
||||||
|
cy.add({
|
||||||
|
group: 'nodes',
|
||||||
|
data: {
|
||||||
|
id: 'person-' + person.pk.toString(),
|
||||||
|
name: person.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all :class:`Relationship` records from people:relationship.api.list endpoint.
|
||||||
|
*
|
||||||
|
* @returns JQuery Promise from AJAX
|
||||||
|
*/
|
||||||
|
function get_relationships_ajax() {
|
||||||
|
return $.ajax({
|
||||||
|
url: '{% url "people:relationship.api.list" %}',
|
||||||
|
success: success_relationships_ajax,
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add edges to Cytoscape network from :class:`Relationship` JSON.
|
||||||
|
*
|
||||||
|
* @param data: JSON representation of relationships
|
||||||
|
* @param status: unused
|
||||||
|
* @param xhr: unused
|
||||||
|
*/
|
||||||
|
function success_relationships_ajax(data, status, xhr) {
|
||||||
|
for (var relationship of data) {
|
||||||
|
cy.add({
|
||||||
|
group: 'edges',
|
||||||
|
data: {
|
||||||
|
id: 'relationship-' + relationship.pk.toString(),
|
||||||
|
source: 'person-' + relationship.source.toString(),
|
||||||
|
target: 'person-' + relationship.target.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate a Cytoscape network from :class:`Person` and :class:`Relationship` API.
|
||||||
|
*/
|
||||||
|
function get_network() {
|
||||||
|
cy = cytoscape({
|
||||||
|
container: document.getElementById('cy')
|
||||||
|
});
|
||||||
|
|
||||||
|
$.when(get_people_ajax()).then(function() {
|
||||||
|
get_relationships_ajax()
|
||||||
|
|
||||||
|
}).then(function() {
|
||||||
|
var layout = cy.layout({
|
||||||
|
name: 'circle',
|
||||||
|
randomize: true,
|
||||||
|
animate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
layout.run();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$( window ).on('load', get_network());
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -37,4 +37,16 @@ urlpatterns = [
|
|||||||
path('relationships/<int:relationship_pk>/update',
|
path('relationships/<int:relationship_pk>/update',
|
||||||
views.RelationshipUpdateView.as_view(),
|
views.RelationshipUpdateView.as_view(),
|
||||||
name='relationship.update'),
|
name='relationship.update'),
|
||||||
|
|
||||||
|
path('api/people',
|
||||||
|
views.PersonApiView.as_view(),
|
||||||
|
name='person.api.list'),
|
||||||
|
|
||||||
|
path('api/relationships',
|
||||||
|
views.RelationshipApiView.as_view(),
|
||||||
|
name='relationship.api.list'),
|
||||||
|
|
||||||
|
path('network',
|
||||||
|
views.NetworkView.as_view(),
|
||||||
|
name='network'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ Views for displaying or manipulating models in the 'people' app.
|
|||||||
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views.generic import CreateView, DetailView, FormView, ListView, UpdateView
|
from django.views.generic import CreateView, DetailView, ListView, TemplateView, UpdateView
|
||||||
|
|
||||||
from . import forms, models, permissions
|
from rest_framework.views import APIView, Response
|
||||||
|
|
||||||
|
from . import forms, models, permissions, serializers
|
||||||
|
|
||||||
|
|
||||||
class PersonCreateView(CreateView):
|
class PersonCreateView(CreateView):
|
||||||
@@ -176,3 +178,36 @@ class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, CreateView):
|
|||||||
form.save()
|
form.save()
|
||||||
|
|
||||||
return HttpResponseRedirect(self.relationship.get_absolute_url())
|
return HttpResponseRedirect(self.relationship.get_absolute_url())
|
||||||
|
|
||||||
|
|
||||||
|
class PersonApiView(APIView):
|
||||||
|
"""
|
||||||
|
List all :class:`Person` instances.
|
||||||
|
"""
|
||||||
|
def get(self, request, format=None):
|
||||||
|
"""
|
||||||
|
List all :class:`Person` instances.
|
||||||
|
"""
|
||||||
|
serializer = serializers.PersonSerializer(models.Person.objects.all(),
|
||||||
|
many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class RelationshipApiView(APIView):
|
||||||
|
"""
|
||||||
|
List all :class:`Relationship` instances.
|
||||||
|
"""
|
||||||
|
def get(self, request, format=None):
|
||||||
|
"""
|
||||||
|
List all :class:`Relationship` instances.
|
||||||
|
"""
|
||||||
|
serializer = serializers.RelationshipSerializer(models.Relationship.objects.all(),
|
||||||
|
many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkView(TemplateView):
|
||||||
|
"""
|
||||||
|
View to display relationship network.
|
||||||
|
"""
|
||||||
|
template_name = 'people/network.html'
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ django-bootstrap4==1.1.1
|
|||||||
django-constance==2.6.0
|
django-constance==2.6.0
|
||||||
django-countries==5.5
|
django-countries==5.5
|
||||||
django-dbbackup==3.2.0
|
django-dbbackup==3.2.0
|
||||||
|
django-filter==2.2.0
|
||||||
django-picklefield==2.1.1
|
django-picklefield==2.1.1
|
||||||
django-select2==7.2.0
|
django-select2==7.2.0
|
||||||
django-settings-export==1.2.1
|
django-settings-export==1.2.1
|
||||||
|
djangorestframework==3.11.0
|
||||||
dodgy==0.2.1
|
dodgy==0.2.1
|
||||||
isort==4.3.21
|
isort==4.3.21
|
||||||
lazy-object-proxy==1.4.3
|
lazy-object-proxy==1.4.3
|
||||||
|
|||||||
Reference in New Issue
Block a user