Skip to content

Commit

Permalink
Fixes #260 (gazetteer)
Browse files Browse the repository at this point in the history
  • Loading branch information
capooti committed Mar 16, 2018
1 parent ae537d3 commit 6991c69
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 51 deletions.
27 changes: 27 additions & 0 deletions geonode/contrib/worldmap/gazetteer/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django.contrib import admin

from .models import GazetteerEntry, GazetteerAttribute


class GazetteerEntryAdmin(admin.ModelAdmin):
list_display = (
'layer_name',
'layer_attribute',
'feature_type',
'place_name',
'project',
'username',
)

class GazetteerAttributeAdmin(admin.ModelAdmin):
list_display = (
'layer_name',
'attribute',
'in_gazetteer',
'is_start_date',
'is_end_date',
'date_format',
)

admin.site.register(GazetteerEntry, GazetteerEntryAdmin)
admin.site.register(GazetteerAttribute, GazetteerAttributeAdmin)
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Command(BaseCommand):
"""
args = '[none]'

# TODO update this to new version

def handle(self, *args, **kwargs):
gaz_layers = GazetteerEntry.objects.filter(
username__isnull=True).values('layer_name').distinct()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('layers', '0029_layer_service'),
('gazetteer', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='GazetteerAttribute',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('in_gazetteer', models.BooleanField(default=False)),
('attribute', models.OneToOneField(to='layers.Attribute')),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('gazetteer', '0002_gazetteerattribute'),
]

operations = [
migrations.AddField(
model_name='gazetteerattribute',
name='date_format',
field=models.TextField(null=True, blank=True),
),
migrations.AddField(
model_name='gazetteerattribute',
name='is_end_date',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='gazetteerattribute',
name='is_start_date',
field=models.BooleanField(default=False),
),
]
16 changes: 16 additions & 0 deletions geonode/contrib/worldmap/gazetteer/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.utils.translation import ugettext as _
from django.contrib.gis.db import models

from geonode.layers.models import Attribute

# Querying postgis database for features then saving as django model object is
# significantly slower than doing everything via SQL on postgis database only.
# from django.modelsinspector import add_introspection_rules
Expand All @@ -27,3 +29,17 @@ class GazetteerEntry(models.Model):

class Meta:
unique_together = (("layer_name", "layer_attribute", "feature_fid"))


class GazetteerAttribute(models.Model):
attribute = models.OneToOneField(
Attribute,
blank=False,
null=False)
in_gazetteer = models.BooleanField(default=False)
is_start_date = models.BooleanField(default=False)
is_end_date = models.BooleanField(default=False)
date_format = models.TextField(blank=True, null=True)

def layer_name(self):
return self.attribute.layer.name
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{% extends "geonode_base.html" %}

{% load i18n %}
{% load staticfiles %}
{% load bootstrap_tags %}
{% load base_tags %}
{% load url from future %}

{% block title %}{{ layer.title }} — {{ block.super }}{% endblock %}

{% block body_outer %}

<div class="page-header">
<h2 class="page-title">{{ layer.title }}</h2>
</div>

<p>
{% trans "By adding your layer features to the gazetteer, they will be searchable and viewable by anyone regardless of your layer's security permissions. If you do not choose at least one depict-date field, the system will use the depict-date in the layer metadata (if any)." %}</p>

<form method="POST">

<div class="form-group">
<label for="fields">{% trans "Select fields for this layer to be part of the gazetteer" %}</label>
{% for attribute in gazetteer_attributes %}
<div class="checkbox">
<label>
<input type="checkbox" name="attributes" value="{{ attribute.attribute }}"
{% if attribute.in_gazetteer %}checked{% endif %}>
{{ attribute.attribute }}
</label>
</div>
{% endfor %}
</div>

<label for="optional">{% trans "Optional Parameters" %}</label>

<div class="form-group">
<label for="name">{% trans "Custom Gazetteer Name" %}</label>
<input type="text" class="form-control" id="gazetteer-name" name="gazetteer-name" />
</div>

<div class="form-group">

<label for="start-attribute">{% trans "Start depict-date field" %}</label>
<select class="form-control" id="start-attribute" name="start-attribute" />
<option value="">-----</option>
{% for attribute in gazetteer_attributes %}
{% if attribute.attribute_type != 'xsd:string' %}
<option>{{ attribute.attribute }}</option>
{% endif %}
{% endfor %}
</select>

<label for="sel-start-date-format">{% trans "Date Format (Examples: 'YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD')" %}</label>
<input type="text" class="form-control" id="sel-start-date-format" name="sel-start-date-format" />
</div>

<div class="form-group">

<label for="end-attribute">{% trans "End depict-date field" %}</label>
<select class="form-control" id="end-attribute" name="end-attribute" />
<option value="">-----</option>
{% for attribute in gazetteer_attributes %}
{% if attribute.attribute_type != 'xsd:string' %}
<option>{{ attribute.attribute }}</option>
{% endif %}
{% endfor %}
</select>

<label for="sel-end-date-format">{% trans "Date Format (Examples: 'YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD')" %}</label>
<input type="text" class="form-control" id="sel-end-date-format" name="sel-end-date-format" />
</div>

<div class="form-actions">
<a href="{% url 'layer_detail' layername=resource.alternate %}" class="btn btn-primary">{% trans "Return to Layer" %}</a>
<input type="submit" id="btn_upd_md_up" class="btn btn-primary" value="{% trans "Update Gazetteer" %}"/>
</div>

</form>



{{ block.super }}
{% endblock body_outer %}
9 changes: 6 additions & 3 deletions geonode/contrib/worldmap/gazetteer/urls.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from django.conf.urls import *
from geonode.gazetteer.views import search
from .views import search, edit_layer_gazetteer

urlpatterns = patterns('',
url(r'^(?P<place_name>[^/]+)' +
url(r'^gazetteer/edit/(?P<layername>[^/]*)$',
edit_layer_gazetteer,
name = 'edit_layer_gazetteer'),
url(r'^gazetteer/(?P<place_name>[^/]+)' +
'(/Service/(?P<services>[\w\,]+))?' +
'(/Project/(?P<project>[A-Za-z0-9_-]+))?' +
'(/Map/(?P<map>[\d]+))?' +
'(/Layer/(?P<layer>[A-Za-z0-9_-]+))?' +
'(/StartDate/(?P<start_date>[\d\s\/\-\:]+(\sBC|\sAD)?))?' +
'(/EndDate/(?P<end_date>[\d\s\/\-\:]+(\sBC|\sAD)?))?' +
'(/User/(?P<user>[A-Za-z0-9_-]+))?' +
'(/(?P<format>(json|xml)))?$', search)
'(/(?P<format>(json|xml)))?$', search),
)
50 changes: 27 additions & 23 deletions geonode/contrib/worldmap/gazetteer/utils.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
from array import array
import re
import logging
import psycopg2
from array import array

from geopy import geocoders

from django.contrib.gis.geos.geometry import GEOSGeometry
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404
from geonode.gazetteer.models import GazetteerEntry
#from psycopg2 import extras
from geonode.gazetteer.models import GazetteerEntry
from geopy import geocoders

from django.conf import settings
import psycopg2
from django.db.models import Q
from geonode.maps.models import Layer, MapLayer, Map
from django.core.cache import cache
from geonode.flexidates import parse_julian_date
import re

from geonode.maps.models import Layer, MapLayer, Map
from geonode.layers.models import Attribute
from .flexidates import parse_julian_date
from .models import GazetteerEntry
from .models import GazetteerEntry

GAZETTEER_TABLE = 'gazetteer_gazetteerentry'

Expand Down Expand Up @@ -162,7 +166,7 @@ def delete_from_gazetteer(layer_name):
GazetteerEntry.objects.filter(layer_name__exact=layer_name).delete()


def add_to_gazetteer(layer_name, name_attributes, start_attribute=None,
def add_to_gazetteer(layer, name_attributes, start_attribute=None,
end_attribute=None, project=None, user=None):
"""
Add placenames from a WorldMap layer into the gazetteer.
Expand All @@ -176,16 +180,16 @@ def add_to_gazetteer(layer_name, name_attributes, start_attribute=None,
def get_date_format(date_attribute):
field_name = "l.\"" + date_attribute.attribute + "\""
date_format = []
if "xsd:date" not in date_attribute.attribute_type and date_attribute.date_format is not None:
if "xsd:date" not in date_attribute.attribute_type and date_attribute.gazetteerattribute.date_format is not None:
# This could be in any of multiple formats, and postgresql needs a format pattern to convert it.
# User should supply this format when adding the layer attribute to the gazetteer
date_format.append(
"TO_CHAR(TO_DATE(CAST({name} AS TEXT), '{format}'), 'YYYY-MM-DD BC')".format(
name=field_name, format=date_attribute.date_format)
name=field_name, format=date_attribute.gazetteerattribute.date_format)
)
date_format.append(
"CAST(TO_CHAR(TO_DATE(CAST({name} AS TEXT), '{format}'), 'J') AS integer)".format(
name=field_name, format=date_attribute.date_format)
name=field_name, format=date_attribute.gazetteerattribute.date_format)
)
elif "xsd:date" in date_attribute.attribute_type:
# It's a date, convert to string
Expand All @@ -206,7 +210,7 @@ def get_metadata_format(metadata_date):
metadata_date))
return date_format

layer = get_object_or_404(Layer, name=layer_name)
layer_name = layer.name
layer_type, geocolumn, projection = get_geometry_type(layer)

namelist = "'" + "','".join(name_attributes) + "'"
Expand Down Expand Up @@ -237,7 +241,7 @@ def get_metadata_format(metadata_date):

start_format, julian_start = None, None
if start_attribute is not None:
start_attribute_obj = get_object_or_404(Layer.Attribute, layer=layer, attribute=start_attribute)
start_attribute_obj = get_object_or_404(Attribute, layer=layer, attribute=start_attribute)
start_dates = get_date_format(start_attribute_obj)
start_format = start_dates[0]
julian_start = start_dates[1]
Expand All @@ -246,7 +250,7 @@ def get_metadata_format(metadata_date):

end_format, julian_end = None, None
if end_attribute is not None:
end_attribute_obj = get_object_or_404(Layer.Attribute, layer=layer, attribute=end_attribute)
end_attribute_obj = get_object_or_404(Attribute, layer=layer, attribute=end_attribute)
end_dates = get_date_format(end_attribute_obj)
end_format = end_dates[0]
julian_end = end_dates[1]
Expand Down Expand Up @@ -286,7 +290,7 @@ def get_metadata_format(metadata_date):
"""

for name in name_attributes:
attribute = get_object_or_404(Layer.Attribute, layer=layer, attribute=name)
attribute = get_object_or_404(Attribute, layer=layer, attribute=name)

# detect column type, needed by dblink
cur = conn.cursor(layer.store)
Expand All @@ -298,7 +302,6 @@ def get_metadata_format(metadata_date):
Update layer placenames where placename FID = layer FID
and placename layer attribute = name attribute
"""

updateQuery =updateTemplate.format(
table=GAZETTEER_TABLE,
attribute=attribute.attribute,
Expand Down Expand Up @@ -361,8 +364,6 @@ def get_metadata_format(metadata_date):
conn.close()




def getExternalServiceResults(place_name, services):
results = []
for service in services.split(',', ):
Expand All @@ -379,8 +380,11 @@ def getExternalServiceResults(place_name, services):


def getGoogleResults(place_name):
g = geocoders.GoogleV3(client_id=settings.GOOGLE_API_KEY,
secret_key=settings.GOOGLE_SECRET_KEY) if settings.GOOGLE_SECRET_KEY is not None else geocoders.GoogleV3()
if hasattr(settings, 'GOOGLE_SECRET_KEY'):
g = geocoders.GoogleV3(client_id=settings.GOOGLE_API_KEY,
secret_key=settings.GOOGLE_SECRET_KEY)
else:
g = geocoders.GoogleV3()
try:
results = g.geocode(place_name, exactly_one=False)
formatted_results = []
Expand All @@ -403,7 +407,7 @@ def getNominatimResults(place_name):
return []

def getConnection(layer_store=None):
dbname = settings.DATABASES[settings.GAZETTEER_DB_ALIAS]['NAME']
dbname = settings.DATABASES['default']['NAME']
if layer_store:
dbname = layer_store
return psycopg2.connect(
Expand Down

0 comments on commit 6991c69

Please sign in to comment.