diff --git a/django/contrib/gis/db/models/manager.py b/django/contrib/gis/db/models/manager.py index 80a2ca49f0..5faa259a12 100644 --- a/django/contrib/gis/db/models/manager.py +++ b/django/contrib/gis/db/models/manager.py @@ -6,3 +6,6 @@ class GeoManager(Manager): def get_query_set(self): return GeoQuerySet(model=self.model) + + def kml(self, field_name): + return self.get_query_set().kml(field_name) diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py index 7c911f7aba..6619e54c9a 100644 --- a/django/contrib/gis/db/models/query.py +++ b/django/contrib/gis/db/models/query.py @@ -1,5 +1,8 @@ from django.db.models.query import Q, QuerySet +from django.db import backend +from django.contrib.gis.db.models.fields import GeometryField from django.contrib.gis.db.models.postgis import parse_lookup +from django.db.models.fields import FieldDoesNotExist import operator class GeoQ(Q): @@ -33,3 +36,11 @@ class GeoQuerySet(QuerySet): if len(args) > 0: clone._filters = clone._filters & reduce(operator.and_, map(mapper, args)) return clone + + def kml(self, field_name): + field = self.model._meta.get_field(field_name) + + field_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), + backend.quote_name(field.column)) + + return self.extra(select={'kml':'AsKML(%s,6)' % field_col}) diff --git a/django/contrib/gis/sitemaps.py b/django/contrib/gis/sitemaps.py new file mode 100644 index 0000000000..1ce0493472 --- /dev/null +++ b/django/contrib/gis/sitemaps.py @@ -0,0 +1,62 @@ +from django.core import urlresolvers +from django.contrib.sitemaps import Sitemap +from django.contrib.gis.db.models.fields import GeometryField +from django.db.models import get_model, get_models +from django.template.loader import get_template +from django.template import Context +from django.http import HttpResponse + +kml_files = [('gis.school', 'location'), + ('gis.district', 'boundary')] + + +class KMLSitemap(Sitemap): + """ + A minimal hook to + """ + def __init__(self, locations=None): + if locations is None: + self.locations = _build_kml_sources() + else: + self.locations = locations + + def items(self): + return self.locations + + def location(self, obj): + return urlresolvers.reverse('django.contrib.gis.sitemaps.kml', + kwargs={'label':obj[0], + 'field_name':obj[1]}) + + +def _build_kml_sources(): + "Make a mapping of all available KML sources." + ret = [] + for klass in get_models(): + for field in klass._meta.fields: + if isinstance(field, GeometryField): + label = "%s.%s" % (klass._meta.app_label, + klass._meta.module_name) + + ret.append((label, field.name)) + return ret + + +class KMLNotFound(Exception): + pass + + +def kml(request, label, field_name): + placemarks = [] + klass = get_model(*label.split('.')) + if not klass: + raise KMLNotFound("You must supply a valid app.model label. Got %s" % label) + #FIXME: GMaps apparently has a limit on size of displayed kml files + # check if paginating w/ external refs (i.e. linked list) helps. + placemarks.extend(list(klass._default_manager.kml(field_name)[:100])) + #FIXME: other KML features? + t = get_template('gis/kml.xml') + c = Context({'places':placemarks}) + + return HttpResponse(t.render(c), mimetype='application/vnd.google-earth.kml+xml') + diff --git a/django/contrib/gis/templates/gis/kml.xml b/django/contrib/gis/templates/gis/kml.xml new file mode 100644 index 0000000000..7d121c2aa1 --- /dev/null +++ b/django/contrib/gis/templates/gis/kml.xml @@ -0,0 +1,10 @@ + + + {% for place in places %} + + {{ place.name|escape }} + {{ place.description|escape }} + {{ place.kml }} + + {% endfor %} + diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py index 30949837e4..0671e3aa13 100644 --- a/django/contrib/sitemaps/__init__.py +++ b/django/contrib/sitemaps/__init__.py @@ -88,3 +88,24 @@ class GenericSitemap(Sitemap): if self.date_field is not None: return getattr(item, self.date_field) return None + + +class KMLSitemap(Sitemap): + """ + A minimal hook to + """ + def __init__(self, locations=None): + if locations is None: + self.locations = [] + else: + self.locations = locations + + def items(self): + return self.locations + + def location(self, obj): + urlresolvers.reverse('django.contrib.gis.sitemaps.kml', + kwargs={'label':obj[0], + 'field':obj[1]}) + +