--- /dev/null
+# -*- 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'),
+ ),
+ ]
--- /dev/null
+# -*- 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'),
+ ),
+ ]
--- /dev/null
+# -*- 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),
+ ),
+ ]
--- /dev/null
+# -*- 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'),
+ ),
+ ]
--- /dev/null
+# -*- 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'),
+ ),
+ ]
--- /dev/null
+# -*- 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'),
+ ),
+ ]
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
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):
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'
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):
url(r'^person/(?P<slug>.*)/$', 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'),
]
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)
--- /dev/null
+{% 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 %}
+ <h1 class="dotted">{% trans "Network" %}</h1>
+{% endblock %}
+
+{% block page_content %}
+
+
+ {% for organization in organizations %}
+
+ {{ organization.name }}<br>
+ {{ organization.lat }}<br>
+ {{ organization.lon }}<br>
+ {{ organization.city }}<br>
+ {{ organization.country.name }}<br>
+
+ <!-- optional -->
+ {% with organization.links|get_type_link:'link' as links %}
+ {% if links %}
+ {{ links.first }}
+ {% endif %}
+ {% endwith %}
+ <br>
+ <!-- optional -->
+ {% with organization.images.all|get_type:'logo' as images %}
+ {% if images %}
+ <img src="{{ MEDIA_URL }}{% thumbnail images.first.file 100 0 left=0 top=0 %}" alt="logo {{ organization.name }}" />
+ {% endif %}
+ {% endwith %}
+ <br><br>
+
+ {% endfor %}
+
+
+
+{% endblock %}