Commit 712bb0dd authored by Justin Bronn's avatar Justin Bronn
Browse files

Fixed KML sitemaps, and added support for generating KMZ and GeoRSS sitemaps;...

Fixed KML sitemaps, and added support for generating KMZ and GeoRSS sitemaps; sitemaps now support Google's Geo Sitemap format.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8502 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent c83a96d2
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
import cStringIO, zipfile
from django.http import HttpResponse
from django.template import loader

def compress_kml(kml):
    "Returns compressed KMZ from the given KML string."
    kmz = cStringIO.StringIO()
    zf = zipfile.ZipFile(kmz, 'a', zipfile.ZIP_DEFLATED, False)
    zf.writestr('doc.kml', kml)
    zf.close()
    kmz.seek(0)
    return kmz.read()

def render_to_kml(*args, **kwargs):
    "Renders the response using the MIME type for KML."
    "Renders the response as KML (using the correct MIME type)."
    return HttpResponse(loader.render_to_string(*args, **kwargs),
                        mimetype='application/vnd.google-earth.kml+xml kml')

def render_to_kmz(*args, **kwargs):
    """
    Compresses the KML content and returns as KMZ (using the correct 
    MIME type).
    """
    return HttpResponse(compress_kml(loader.render_to_string(*args, **kwargs)),
                        mimetype='application/vnd.google-earth.kmz')


def render_to_text(*args, **kwargs):
    "Renders the response using the MIME type for plain text."
    return HttpResponse(loader.render_to_string(*args, **kwargs),

django/contrib/gis/sitemaps.py

deleted100644 → 0
+0 −55
Original line number Diff line number Diff line
from django.core import urlresolvers
from django.contrib.sitemaps import Sitemap
from django.contrib.gis.db.models.fields import GeometryField
from django.contrib.gis.shortcuts import render_to_kml
from django.db.models import get_model, get_models
from django.http import HttpResponse

class KMLSitemap(Sitemap):
    """
    A minimal hook to produce KML sitemaps.
    """
    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?
    return render_to_kml('gis/kml/placemarks.kml', {'places' : placemarks})

    
+4 −0
Original line number Diff line number Diff line
# Geo-enabled Sitemap classes.
from django.contrib.gis.sitemaps.georss import GeoRSSSitemap
from django.contrib.gis.sitemaps.kml import KMLSitemap, KMZSitemap
+53 −0
Original line number Diff line number Diff line
from django.core import urlresolvers
from django.contrib.sitemaps import Sitemap

class GeoRSSSitemap(Sitemap):
    """
    A minimal hook to produce sitemaps for GeoRSS feeds.
    """
    def __init__(self, feed_dict, slug_dict=None):
        """
        This sitemap object initializes on a feed dictionary (as would be passed
        to `django.contrib.syndication.views.feed`) and a slug dictionary.  
        If the slug dictionary is not defined, then it's assumed the keys provide
        the URL parameter to the feed.  However, if you have a complex feed (e.g.,
        you override `get_object`, then you'll need to provide a slug dictionary.
        The slug dictionary should have the same keys as the feed dictionary, but 
        each value in the slug dictionary should be a sequence of slugs that may 
        be used for valid feeds.  For example, let's say we have a feed that 
        returns objects for a specific ZIP code in our feed dictionary:

            feed_dict = {'zipcode' : ZipFeed}

        Then we would use a slug dictionary with a list of the zip code slugs
        corresponding to feeds you want listed in the sitemap:

            slug_dict = {'zipcode' : ['77002', '77054']}
        """
        # Setting up.
        self.feed_dict = feed_dict
        self.locations = []
        if slug_dict is None: slug_dict = {}
        # Getting the feed locations.
        for section in feed_dict.keys():
            if slug_dict.get(section, False):
                for slug in slug_dict[section]:
                    self.locations.append(('%s/%s' % (section, slug)))
            else:
                self.locations.append(section)
 
    def get_urls(self, page=1):
        """
        This method is overrridden so the appropriate `geo_format` attribute
        is placed on each URL element.
        """
        urls = Sitemap.get_urls(self)
        for url in urls: url['geo_format'] = 'georss'
        return urls

    def items(self):
        return self.locations

    def location(self, obj):
        return urlresolvers.reverse('django.contrib.syndication.views.feed',
                                    args=(obj,), kwargs={'feed_dict' : self.feed_dict})
+63 −0
Original line number Diff line number Diff line
from django.core import urlresolvers
from django.contrib.sitemaps import Sitemap
from django.contrib.gis.db.models.fields import GeometryField
from django.db import models

class KMLSitemap(Sitemap):
    """
    A minimal hook to produce KML sitemaps.
    """
    geo_format = 'kml'

    def __init__(self, locations=None):
        # If no locations specified, then we try to build for
        # every model in installed applications.
        self.locations = self._build_kml_sources(locations)
        
    def _build_kml_sources(self, sources):
        """
        Goes through the given sources and returns a 3-tuple of
        the application label, module name, and field name of every
        GeometryField encountered in the sources.

        If no sources are provided, then all models.
        """
        kml_sources = []
        if sources is None:
            sources = models.get_models()
        for source in sources:
            if isinstance(source, models.base.ModelBase):
                for field in source._meta.fields:
                    if isinstance(field, GeometryField):
                        kml_sources.append((source._meta.app_label,
                                            source._meta.module_name,
                                            field.name))
            elif isinstance(source, (list, tuple)):
                if len(source) != 3: 
                    raise ValueError('Must specify a 3-tuple of (app_label, module_name, field_name).')
                kml_sources.append(source)
            else:
                raise TypeError('KML Sources must be a model or a 3-tuple.')
        return kml_sources

    def get_urls(self, page=1):
        """
        This method is overrridden so the appropriate `geo_format` attribute
        is placed on each URL element.
        """
        urls = Sitemap.get_urls(self, page=page)
        for url in urls: url['geo_format'] = self.geo_format
        return urls

    def items(self):
        return self.locations

    def location(self, obj):
        return urlresolvers.reverse('django.contrib.gis.sitemaps.views.%s' % self.geo_format,
                                    kwargs={'label' : obj[0], 
                                            'model' : obj[1],
                                            'field_name': obj[2],
                                            }
                                    )
class KMZSitemap(KMLSitemap):
    geo_format = 'kmz'
Loading