Django

Code

Changeset 5806

Show
Ignore:
Timestamp:
08/05/07 20:27:22 (1 year ago)
Author:
jbronn
Message:

gis: added tests, added precision keyword, and generally improved GeoQuerySet?.kml(); commented, improved, and added tests for GeometryProxy?.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis/django/contrib/gis/db/backend/postgis/__init__.py

    r5776 r5806  
    22  The PostGIS spatial database backend module. 
    33""" 
    4 from query import get_geo_where_clause, GEOM_FUNC_PREFIX, POSTGIS_TERMS 
     4from query import \ 
     5    get_geo_where_clause, GEOM_FUNC_PREFIX, POSTGIS_TERMS, \ 
     6    MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2 
    57from creation import create_spatial_db 
    68from field import PostGISField 
    79 
     10# Whether PostGIS has AsKML() support. 
     11if MAJOR_VERSION == 1: 
     12    # AsKML() only supported in versions 1.2.1+ 
     13    if MINOR_VERSION1 == 3: 
     14        ASKML = 'ST_AsKML' 
     15    elif MINOR_VERSION1 == 2 and MINOR_VERSION2 >= 1: 
     16        ASKML = 'AsKML' 
     17     
  • django/branches/gis/django/contrib/gis/db/models/manager.py

    r5751 r5806  
    88        return GeoQuerySet(model=self.model) 
    99 
    10     def kml(self, field_name): 
    11         return self.get_query_set().kml(field_name
     10    def kml(self, field_name, **kwargs): 
     11        return self.get_query_set().kml(field_name, **kwargs
  • django/branches/gis/django/contrib/gis/db/models/proxy.py

    r5762 r5806  
    11""" 
    2   The GeometryProxy object, allows for lazy-geometries. 
     2  The GeometryProxy object, allows for lazy-geometries.  The proxy uses 
     3   Python descriptors for instantiating and setting GEOS Geometry objects 
     4   corresponding to geographic model fields. 
    35 
    46  Thanks to Robert Coup for providing this functionality (see #4322). 
    57""" 
    68 
    7 # GEOS Routines  
     9from types import NoneType, StringType, UnicodeType 
    810from django.contrib.gis.geos import GEOSGeometry, GEOSException  
    911 
    10 # TODO: docstrings & comments 
     12# TODO: docstrings 
    1113class GeometryProxy(object):  
    1214    def __init__(self, field):  
     15        "Proxy initializes on the given GeometryField." 
    1316        self._field = field  
    1417      
    1518    def __get__(self, obj, type=None):  
     19        # Getting the value of the field. 
    1620        geom_value = obj.__dict__[self._field.attname]  
     21 
    1722        if (geom_value is None) or (isinstance(geom_value, GEOSGeometry)):  
     23            # If the value of the field is None, or is already a GEOS Geometry 
     24            #  no more work is needed. 
    1825            geom = geom_value  
    1926        else:  
    20             geom = GEOSGeometry(geom_value)  
     27            # Otherwise, a GEOSGeometry object is built using the field's contents, 
     28            #  and the model's corresponding attribute is set. 
     29            geom = GEOSGeometry(geom_value) 
    2130            setattr(obj, self._field.attname, geom)  
    2231        return geom  
    2332      
    2433    def __set__(self, obj, value):  
    25         if isinstance(value, GEOSGeometry):  
    26             if value and ((value.srid is None) and (self._field._srid is not None)):  
    27                 value.srid = self._field._srid 
    28       
     34        if isinstance(value, GEOSGeometry) and (value.geom_type.upper() == self._field._geom): 
     35            # Getting set with GEOS Geometry; geom_type must match that of the field. 
     36 
     37            # If value's SRID is not set, setting it to the field's SRID. 
     38            if value.srid is None: value.srid = self._field._srid 
     39        elif isinstance(value, (NoneType, StringType, UnicodeType)): 
     40            # Getting set with None, WKT, or HEX 
     41            pass 
     42        else: 
     43            raise TypeError, 'cannot set %s GeometryProxy with value of type: %s' % (self._field._geom, type(value)) 
    2944        obj.__dict__[self._field.attname] = value  
    3045        return value  
  • django/branches/gis/django/contrib/gis/db/models/query.py

    r5776 r5806  
     1import operator 
     2from django.core.exceptions import ImproperlyConfigured 
     3from django.db import backend 
    14from django.db.models.query import Q, QuerySet 
    2 from django.db import backend 
     5from django.db.models.fields import FieldDoesNotExist 
    36from django.contrib.gis.db.models.fields import GeometryField 
    47from django.contrib.gis.db.backend import parse_lookup # parse_lookup depends on the spatial database backend. 
    5 from django.db.models.fields import FieldDoesNotExist 
    6 import operator 
    78 
    89class GeoQ(Q): 
     
    3839        return clone 
    3940 
    40     def kml(self, field_name): 
     41    def kml(self, field_name, precision=8): 
     42        """Returns KML representation of the given field name in a `kml`  
     43        attribute on each element of the QuerySet.""" 
     44        # Is KML output supported? 
     45        try: 
     46            from django.contrib.gis.db.backend.postgis import ASKML 
     47        except ImportError: 
     48            raise ImproperlyConfigured, 'AsKML() only available in PostGIS versions 1.2.1 and greater.' 
     49 
     50        # Is the given field name a geographic field? 
    4151        field = self.model._meta.get_field(field_name) 
    42  
     52        if not isinstance(field, GeometryField): 
     53            raise TypeError, 'KML output only available on GeometryField fields.' 
    4354        field_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), 
    44                             backend.quote_name(field.column)) 
     55                               backend.quote_name(field.column)) 
    4556         
    46         return self.extra(select={'kml':'AsKML(%s,6)' % field_col}) 
     57        # Adding the AsKML function call to the SELECT part of the SQL. 
     58        return self.extra(select={'kml':'%s(%s,%s)' % (ASKML, field_col, precision)}) 
  • django/branches/gis/django/contrib/gis/tests/geoapp/tests.py

    r5776 r5806  
    11import unittest 
    22from models import Country, City, State 
    3 from django.contrib.gis.geos import fromstr 
     3from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Polygon 
    44 
    55class GeoModelTest(unittest.TestCase): 
    66     
    7     def test001_initial_sql(self): 
     7    def test01_initial_sql(self): 
    88        "Testing geographic initial SQL." 
    99 
     
    1313        self.assertEqual(3, State.objects.count()) 
    1414 
    15     def test002_contains_contained(self): 
     15    def test02_proxy(self): 
     16        "Testing Lazy-Geometry support (using the GeometryProxy)." 
     17        #### Testing on a Point 
     18        pnt = Point(0, 0) 
     19        nullcity = City(name='NullCity', point=pnt) 
     20        nullcity.save() 
     21 
     22        # Making sure TypeError is thrown when trying to set with an 
     23        #  incompatible type. 
     24        for bad in [5, 2.0, LineString((0, 0), (1, 1))]: 
     25            try: 
     26                nullcity.point = bad 
     27            except TypeError: 
     28                pass 
     29            else: 
     30                self.fail('Should throw a TypeError') 
     31 
     32        # Now setting with a compatible GEOS Geometry, saving, and ensuring 
     33        #  the save took, notice no SRID is explicitly set. 
     34        new = Point(5, 23) 
     35        nullcity.point = new 
     36 
     37        # Ensuring that the SRID is automatically set to that of the  
     38        #  field after assignment, but before saving. 
     39        self.assertEqual(4326, nullcity.point.srid) 
     40        nullcity.save() 
     41 
     42        # Ensuring the point was saved correctly after saving 
     43        self.assertEqual(new, City.objects.get(name='NullCity').point) 
     44 
     45        # Setting the X and Y of the Point 
     46        nullcity.point.x = 23 
     47        nullcity.point.y = 5 
     48        # Checking assignments pre & post-save. 
     49        self.assertNotEqual(Point(23, 5), City.objects.get(name='NullCity').point) 
     50        nullcity.save() 
     51        self.assertEqual(Point(23, 5), City.objects.get(name='NullCity').point) 
     52        nullcity.delete() 
     53 
     54        #### Testing on a Polygon 
     55        shell = LinearRing((0, 0), (0, 100), (100, 100), (100, 0), (0, 0)) 
     56        inner = LinearRing((40, 40), (40, 60), (60, 60), (60, 40), (40, 40)) 
     57 
     58        # Creating a State object using a built Polygon 
     59        ply = Polygon(shell.clone(), inner.clone()) 
     60        nullstate = State(name='NullState', poly=ply) 
     61        self.assertEqual(4326, nullstate.poly.srid) # SRID auto-set from None 
     62        nullstate.save() 
     63        self.assertEqual(ply, State.objects.get(name='NullState').poly) 
     64         
     65        # Changing the interior ring on the poly attribute. 
     66        new_inner = LinearRing((30, 30), (30, 70), (70, 70), (70, 30), (30, 30)) 
     67        nullstate.poly[1] = new_inner.clone() 
     68        ply[1] = new_inner 
     69        self.assertEqual(4326, nullstate.poly.srid) 
     70        nullstate.save() 
     71        self.assertEqual(ply, State.objects.get(name='NullState').poly) 
     72        nullstate.delete() 
     73 
     74    def test03_kml(self): 
     75        "Testing KML output from the database using GeoManager.kml()." 
     76        # Should throw an error trying to get KML from a non-geometry field. 
     77        try: 
     78            qs = City.objects.all().kml('name') 
     79        except TypeError: 
     80            pass 
     81        else: 
     82            self.fail('Expected a TypeError exception') 
     83 
     84        # Ensuring the KML is as expected. 
     85        ptown = City.objects.kml('point', precision=9).get(name='Pueblo') 
     86        self.assertEqual('<Point><coordinates>-104.609252,38.255001,0</coordinates></Point>', ptown.kml) 
     87 
     88    def test10_contains_contained(self): 
    1689        "Testing the 'contained' and 'contains' lookup types." 
    1790 
     
    48121        self.assertEqual(0, len(Country.objects.filter(mpoly__contains=okcity.point.wkt))) # Qeury w/WKT 
    49122 
    50     def test003_lookup_insert_transform(self): 
     123    def test11_lookup_insert_transform(self): 
    51124        "Testing automatic transform for lookups and inserts." 
    52125 
     
    70143        self.assertAlmostEqual(wgs_pnt.y, sa.point.y, 6) 
    71144 
    72     def test004_null_geometries(self): 
     145    def test12_null_geometries(self): 
    73146        "Testing NULL geometry support." 
    74147 
     
    91164        nmi.save() 
    92165     
    93     def test005_left_right(self): 
     166    def test13_left_right(self): 
    94167        "Testing the 'left' and 'right' lookup types." 
    95168         
  • django/branches/gis/django/contrib/gis/utils/LayerMapping.py

    r5755 r5806  
    269269            ct = CoordTransform(self.source_srs, target_srs) 
    270270        except Exception, msg: 
    271             raise Exception, 'Could not translate between the data source and model geometry.' 
     271            raise Exception, 'Could not translate between the data source and model geometry: %s' % msg 
    272272 
    273273        for feat in self.layer: