mirror of
https://github.com/Southampton-RSG/breccia-mapper.git
synced 2026-03-03 03:17:07 +00:00
feat: add views for Organisation model
Location picker on update view
This commit is contained in:
@@ -24,6 +24,17 @@ def get_date_year_range() -> typing.Iterable[int]:
|
||||
return range(this_year, this_year - num_years_display, -1)
|
||||
|
||||
|
||||
class OrganisationForm(forms.ModelForm):
|
||||
"""Form for creating / updating an instance of :class:`Organisation`."""
|
||||
class Meta:
|
||||
model = models.Organisation
|
||||
fields = [
|
||||
'name',
|
||||
'latitude',
|
||||
'longitude'
|
||||
]
|
||||
|
||||
|
||||
class PersonForm(forms.ModelForm):
|
||||
"""Form for creating / updating an instance of :class:`Person`."""
|
||||
class Meta:
|
||||
|
||||
@@ -64,9 +64,7 @@ class User(AbstractUser):
|
||||
|
||||
|
||||
class Organisation(models.Model):
|
||||
"""
|
||||
Organisation to which a :class:`Person` belongs.
|
||||
"""
|
||||
"""Organisation to which a :class:`Person` belongs."""
|
||||
name = models.CharField(max_length=255, blank=False, null=False)
|
||||
|
||||
#: Latitude for displaying location on a map
|
||||
@@ -78,6 +76,9 @@ class Organisation(models.Model):
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('people:organisation.detail', kwargs={'pk': self.pk})
|
||||
|
||||
|
||||
class Theme(models.Model):
|
||||
"""
|
||||
|
||||
29
people/templates/people/organisation/create.html
Normal file
29
people/templates/people/organisation/create.html
Normal file
@@ -0,0 +1,29 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'people:organisation.list' %}">Organisations</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Create</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>New Organisation</h1>
|
||||
|
||||
<hr>
|
||||
|
||||
<form class="form"
|
||||
method="POST">
|
||||
{% csrf_token %}
|
||||
|
||||
{% load bootstrap4 %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
{% buttons %}
|
||||
<button class="btn btn-success" type="submit">Submit</button>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
36
people/templates/people/organisation/detail.html
Normal file
36
people/templates/people/organisation/detail.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block extra_head %}
|
||||
{{ map_markers|json_script:'map-markers' }}
|
||||
|
||||
{% load staticfiles %}
|
||||
<script src="{% static 'js/map.js' %}"></script>
|
||||
|
||||
<script async defer src="https://maps.googleapis.com/maps/api/js?key={{ settings.GOOGLE_MAPS_API_KEY }}&callback=initMap"
|
||||
type="text/javascript"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'people:organisation.list' %}">Organisations</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ object }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>{{ organisation.name }}</h1>
|
||||
|
||||
<hr>
|
||||
|
||||
<a class="btn btn-success"
|
||||
href="{% url 'people:organisation.update' pk=organisation.pk %}">Update</a>
|
||||
|
||||
<hr>
|
||||
|
||||
<div id="map" style="height: 800px; width: 100%"></div>
|
||||
|
||||
<hr>
|
||||
|
||||
{% endblock %}
|
||||
42
people/templates/people/organisation/list.html
Normal file
42
people/templates/people/organisation/list.html
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item active" aria-current="page">Organisation</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>People</h1>
|
||||
|
||||
<hr>
|
||||
|
||||
<a class="btn btn-success"
|
||||
href="{% url 'people:organisation.create' %}">New Organisation</a>
|
||||
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for organisation in organisation_list.all %}
|
||||
<tr>
|
||||
<td>{{ organisation }}</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-info"
|
||||
href="{% url 'people:organisation.detail' pk=organisation.pk %}">Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>No records</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
68
people/templates/people/organisation/update.html
Normal file
68
people/templates/people/organisation/update.html
Normal file
@@ -0,0 +1,68 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block extra_head %}
|
||||
{% load staticfiles %}
|
||||
<script type="application/javascript">
|
||||
const data = [
|
||||
{
|
||||
name: '{{ organisation.name }}',
|
||||
lat: '{{ organisation.latitude }}',
|
||||
lng: '{{ organisation.longitude }}'
|
||||
},
|
||||
]
|
||||
|
||||
const settings = {
|
||||
zoom: 2,
|
||||
centre_lat: '{{ organisation.latitude }}',
|
||||
centre_lng: '{{ organisation.longitude }}',
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- {{ map_markers|json_script:'map-markers' }} -->
|
||||
|
||||
<script src="{% static 'js/location_picker.js' %}"></script>
|
||||
|
||||
<script async defer src="https://maps.googleapis.com/maps/api/js?key={{ settings.GOOGLE_MAPS_API_KEY }}&callback=initMap&libraries=places"
|
||||
type="text/javascript"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'people:organisation.list' %}">Organisations</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'people:organisation.detail' pk=organisation.pk %}">{{ organisation }}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Update</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>{{ organisation.name }}</h1>
|
||||
|
||||
<hr>
|
||||
|
||||
<form class="form"
|
||||
method="POST">
|
||||
{% csrf_token %}
|
||||
|
||||
{% load bootstrap4 %}
|
||||
{% bootstrap_form form exclude='latitude,longitude' %}
|
||||
|
||||
{% bootstrap_field form.latitude %}
|
||||
{% bootstrap_field form.longitude %}
|
||||
|
||||
{% buttons %}
|
||||
<button class="btn btn-success" type="submit">Submit</button>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<input id="location-search" class="controls" type="text" placeholder="Location Search"/>
|
||||
<div id="map" style="height: 800px; width: 100%"></div>
|
||||
|
||||
<hr>
|
||||
|
||||
{% endblock %}
|
||||
@@ -6,6 +6,22 @@ from . import views
|
||||
app_name = 'people'
|
||||
|
||||
urlpatterns = [
|
||||
path('organisations/create',
|
||||
views.organisation.OrganisationCreateView.as_view(),
|
||||
name='organisation.create'),
|
||||
|
||||
path('organisations',
|
||||
views.organisation.OrganisationListView.as_view(),
|
||||
name='organisation.list'),
|
||||
|
||||
path('organisations/<int:pk>',
|
||||
views.organisation.OrganisationDetailView.as_view(),
|
||||
name='organisation.detail'),
|
||||
|
||||
path('organisations/<int:pk>/update',
|
||||
views.organisation.OrganisationUpdateView.as_view(),
|
||||
name='organisation.update'),
|
||||
|
||||
path('profile/',
|
||||
views.person.ProfileView.as_view(),
|
||||
name='person.profile'),
|
||||
|
||||
@@ -4,6 +4,7 @@ Views for displaying or manipulating models within the `people` app.
|
||||
|
||||
from . import (
|
||||
network,
|
||||
organisation,
|
||||
person,
|
||||
relationship
|
||||
)
|
||||
@@ -11,6 +12,7 @@ from . import (
|
||||
|
||||
__all__ = [
|
||||
'network',
|
||||
'organisation',
|
||||
'person',
|
||||
'relationship',
|
||||
]
|
||||
|
||||
47
people/views/organisation.py
Normal file
47
people/views/organisation.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import typing
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic import CreateView, DetailView, ListView, UpdateView
|
||||
|
||||
from people import forms, models
|
||||
|
||||
|
||||
class OrganisationCreateView(LoginRequiredMixin, CreateView):
|
||||
"""View to create a new instance of :class:`Organisation`."""
|
||||
model = models.Organisation
|
||||
template_name = 'people/organisation/create.html'
|
||||
form_class = forms.OrganisationForm
|
||||
|
||||
|
||||
class OrganisationListView(LoginRequiredMixin, ListView):
|
||||
"""View displaying a list of :class:`organisation` objects."""
|
||||
model = models.Organisation
|
||||
template_name = 'people/organisation/list.html'
|
||||
|
||||
|
||||
class OrganisationDetailView(LoginRequiredMixin, DetailView):
|
||||
"""View displaying details of a :class:`Organisation`."""
|
||||
model = models.Organisation
|
||||
context_object_name = 'organisation'
|
||||
template_name = 'people/organisation/detail.html'
|
||||
|
||||
def get_context_data(self,
|
||||
**kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
|
||||
"""Add map marker to context."""
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['map_markers'] = [{
|
||||
'name': self.object.name,
|
||||
'lat': self.object.latitude,
|
||||
'lng': self.object.longitude,
|
||||
}]
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class OrganisationUpdateView(LoginRequiredMixin, UpdateView):
|
||||
"""View for updating a :class:`Organisation` record."""
|
||||
model = models.Organisation
|
||||
context_object_name = 'organisation'
|
||||
template_name = 'people/organisation/update.html'
|
||||
form_class = forms.OrganisationForm
|
||||
Reference in New Issue
Block a user