From: Emilie Date: Wed, 5 Oct 2016 14:07:19 +0000 (+0200) Subject: Network : list geocoded organization X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=798bc59e49b678ec5a24a8c91172fd659ab91bc4;p=mezzo.git Network : list geocoded organization --- diff --git a/app/organization/network/migrations/0031_auto_20161005_1403.py b/app/organization/network/migrations/0031_auto_20161005_1403.py new file mode 100644 index 00000000..09945c16 --- /dev/null +++ b/app/organization/network/migrations/0031_auto_20161005_1403.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-10-05 12:03 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0030_team_parent'), + ] + + operations = [ + migrations.AlterField( + model_name='organization', + name='is_on_map', + field=models.BooleanField(default=False, verbose_name='is on map'), + ), + ] diff --git a/app/organization/network/migrations/0032_auto_20161005_1412.py b/app/organization/network/migrations/0032_auto_20161005_1412.py new file mode 100644 index 00000000..6f0f3572 --- /dev/null +++ b/app/organization/network/migrations/0032_auto_20161005_1412.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-10-05 12:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0031_auto_20161005_1403'), + ] + + operations = [ + migrations.AddField( + model_name='organization', + name='latitude', + field=models.CharField(blank=True, max_length=40, verbose_name='latitude'), + ), + migrations.AddField( + model_name='organization', + name='longitude', + field=models.CharField(blank=True, max_length=40, verbose_name='longitude'), + ), + ] diff --git a/app/organization/network/migrations/0033_auto_20161005_1427.py b/app/organization/network/migrations/0033_auto_20161005_1427.py new file mode 100644 index 00000000..7a0fb063 --- /dev/null +++ b/app/organization/network/migrations/0033_auto_20161005_1427.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-10-05 12:27 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0032_auto_20161005_1412'), + ] + + operations = [ + migrations.RemoveField( + model_name='organization', + name='latitude', + ), + migrations.RemoveField( + model_name='organization', + name='longitude', + ), + migrations.AddField( + model_name='organization', + name='lat', + field=models.DecimalField(blank=True, decimal_places=7, help_text='Calculated automatically if mappable location is set.', max_digits=10, null=True, verbose_name='Latitude'), + ), + migrations.AddField( + model_name='organization', + name='lon', + field=models.DecimalField(blank=True, decimal_places=7, help_text='Calculated automatically if mappable location is set.', max_digits=10, null=True, verbose_name='Longitude'), + ), + migrations.AddField( + model_name='organization', + name='mappable_location', + field=models.CharField(blank=True, help_text='This address will be used to calculate latitude and longitude. Leave blank and set Latitude and Longitude to specify the location yourself, or leave all three blank to auto-fill from the Location field.', max_length=128), + ), + ] diff --git a/app/organization/network/migrations/0034_organization_city.py b/app/organization/network/migrations/0034_organization_city.py new file mode 100644 index 00000000..b773c3b1 --- /dev/null +++ b/app/organization/network/migrations/0034_organization_city.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-10-05 12:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0033_auto_20161005_1427'), + ] + + operations = [ + migrations.AddField( + model_name='organization', + name='city', + field=models.CharField(blank=True, max_length=255, verbose_name='city'), + ), + ] diff --git a/app/organization/network/migrations/0035_auto_20161005_1457.py b/app/organization/network/migrations/0035_auto_20161005_1457.py new file mode 100644 index 00000000..5fe10c25 --- /dev/null +++ b/app/organization/network/migrations/0035_auto_20161005_1457.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-10-05 12:57 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0034_organization_city'), + ] + + operations = [ + migrations.AlterField( + model_name='organization', + name='address', + field=models.TextField(verbose_name='address'), + ), + ] diff --git a/app/organization/network/migrations/0036_auto_20161005_1509.py b/app/organization/network/migrations/0036_auto_20161005_1509.py new file mode 100644 index 00000000..7ad0e2b3 --- /dev/null +++ b/app/organization/network/migrations/0036_auto_20161005_1509.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-10-05 13:09 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0035_auto_20161005_1457'), + ] + + operations = [ + migrations.AlterField( + model_name='organization', + name='city', + field=models.CharField(max_length=255, verbose_name='city'), + ), + migrations.AlterField( + model_name='organization', + name='postal_code', + field=models.CharField(max_length=16, verbose_name='postal code'), + ), + ] diff --git a/app/organization/network/models.py b/app/organization/network/models.py index 30d83432..95e8732f 100644 --- a/app/organization/network/models.py +++ b/app/organization/network/models.py @@ -9,11 +9,15 @@ import string import datetime import mimetypes +from geopy.geocoders import GoogleV3 as GoogleMaps +from geopy.exc import GeocoderQueryError + from django.db import models from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse, reverse_lazy from django.conf import settings from django.contrib.auth.models import User +from django.core.exceptions import ValidationError from mezzanine.pages.models import Page from mezzanine.core.models import RichText, Displayable, Slugged @@ -60,8 +64,9 @@ ALIGNMENT_CHOICES = (('left', _('left')), ('left', _('left')), ('right', _('righ class Address(models.Model): """(Address description)""" - address = models.TextField(_('address'), blank=True) - postal_code = models.CharField(_('postal code'), max_length=16, blank=True) + address = models.TextField(_('address')) + postal_code = models.CharField(_('postal code'), max_length=16) + city = models.CharField(_('city'), max_length=255) country = CountryField(_('country')) def __str__(self): @@ -74,8 +79,11 @@ class Address(models.Model): class Organization(Named, Address, URL, AdminThumbRelatedMixin): """(Organization description)""" + mappable_location = models.CharField(max_length=128, blank=True, help_text="This address will be used to calculate latitude and longitude. Leave blank and set Latitude and Longitude to specify the location yourself, or leave all three blank to auto-fill from the Location field.") + lat = models.DecimalField(max_digits=10, decimal_places=7, blank=True, null=True, verbose_name="Latitude", help_text="Calculated automatically if mappable location is set.") + lon = models.DecimalField(max_digits=10, decimal_places=7, blank=True, null=True, verbose_name="Longitude", help_text="Calculated automatically if mappable location is set.") type = models.ForeignKey('OrganizationType', verbose_name=_('organization type'), blank=True, null=True, on_delete=models.SET_NULL) - is_on_map = models.BooleanField(_('is on map'), default=True) + is_on_map = models.BooleanField(_('is on map'), default=False) admin_thumb_type = 'logo' @@ -83,6 +91,39 @@ class Organization(Named, Address, URL, AdminThumbRelatedMixin): verbose_name = _('organization') ordering = ['name',] + def clean(self): + """ + Validate set/validate mappable_location, longitude and latitude. + """ + super(Organization, self).clean() + + if self.lat and not self.lon: + raise ValidationError("Longitude required if specifying latitude.") + + if self.lon and not self.lat: + raise ValidationError("Latitude required if specifying longitude.") + + if not (self.lat and self.lon) and not self.mappable_location: + self.mappable_location = self.address.replace("\n"," ").replace('\r', ' ') + ", " + self.postal_code + " " + self.city + + if self.mappable_location and not (self.lat and self.lon): #location should always override lat/long if set + g = GoogleMaps(domain=settings.EVENT_GOOGLE_MAPS_DOMAIN) + try: + mappable_location, (lat, lon) = g.geocode(self.mappable_location) + except GeocoderQueryError as e: + raise ValidationError("The mappable location you specified could not be found on {service}: \"{error}\" Try changing the mappable location, removing any business names, or leaving mappable location blank and using coordinates from getlatlon.com.".format(service="Google Maps", error=e.message)) + except ValueError as e: + raise ValidationError("The mappable location you specified could not be found on {service}: \"{error}\" Try changing the mappable location, removing any business names, or leaving mappable location blank and using coordinates from getlatlon.com.".format(service="Google Maps", error=e.message)) + except TypeError as e: + raise ValidationError("The mappable location you specified could not be found. Try changing the mappable location, removing any business names, or leaving mappable location blank and using coordinates from getlatlon.com.") + self.mappable_location = mappable_location + self.lat = lat + self.lon = lon + + def save(self): + self.clean() + super(Organization, self).save() + class OrganizationAudio(Audio): diff --git a/app/organization/network/urls.py b/app/organization/network/urls.py index f3900503..fcdf1660 100644 --- a/app/organization/network/urls.py +++ b/app/organization/network/urls.py @@ -13,4 +13,5 @@ urlpatterns = [ url(r'^person/(?P.*)/$', PersonDetailView.as_view(), name="organization-network-person-detail"), url("^person-list-block-autocomplete/$", permission_required('person.can_edit')(PersonListBlockAutocompleteView.as_view()), name='person-list-block-autocomplete'), url("^person-autocomplete/$", permission_required('person.can_edit')(PersonListView.as_view()), name='person-autocomplete'), + url("^network/$", OrganizationListView.as_view(), name='network'), ] diff --git a/app/organization/network/views.py b/app/organization/network/views.py index 13a4d465..acdedca5 100644 --- a/app/organization/network/views.py +++ b/app/organization/network/views.py @@ -52,3 +52,12 @@ class PersonListView(autocomplete.Select2QuerySetView): qs = qs.filter(person_title__istartswith=self.q) return qs + +class OrganizationListView(ListView): + + model = Organization + context_object_name = 'organizations' + template_name='network/organization_list.html' + + def get_queryset(self, **kwargs): + return self.model.objects.filter(is_on_map=True) diff --git a/app/templates/network/organization_list.html b/app/templates/network/organization_list.html new file mode 100644 index 00000000..528a28dd --- /dev/null +++ b/app/templates/network/organization_list.html @@ -0,0 +1,48 @@ +{% extends "pages/page.html" %} +{% load i18n mezzanine_tags keyword_tags pages_tags organization_tags %} + +{% block meta_title %}{% trans "Network" %}{% endblock %} + +{% block meta_description %}{% metablock %} +{{ organization.description }} +{% endmetablock %}{% endblock %} + +{% block page_class %} + organization +{% endblock %} + +{% block page_title %} +

{% trans "Network" %}

+{% endblock %} + +{% block page_content %} + + + {% for organization in organizations %} + + {{ organization.name }}
+ {{ organization.lat }}
+ {{ organization.lon }}
+ {{ organization.city }}
+ {{ organization.country.name }}
+ + + {% with organization.links|get_type_link:'link' as links %} + {% if links %} + {{ links.first }} + {% endif %} + {% endwith %} +
+ + {% with organization.images.all|get_type:'logo' as images %} + {% if images %} + logo {{ organization.name }} + {% endif %} + {% endwith %} +

+ + {% endfor %} + + + +{% endblock %}