Django

Code

Show
Ignore:
Timestamp:
02/10/08 20:25:01 (1 year ago)
Author:
jbronn
Message:

gis: Fixed 6414, and applied DRY to spatial backend internals. Changes include:

(1) Support for distance calculations on geometry fields with geodetic coordinate systems (e.g., WGS84, the default).
(2) The get_db_prep_save and get_db_prep_lookup have been moved from the spatial backends to common implementations in GeometryField.
(3) Simplified SQL construction for GeoQuerySet methods.
(4) SpatialBackend now contains all spatial backend dependent settings.

Files:

Legend:

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

    r6524 r7104  
    22 This object provides the database adaptor for Oracle geometries. 
    33""" 
    4 from cx_Oracle import CLOB 
    5  
    64class OracleSpatialAdaptor(object): 
    75    def __init__(self, geom): 
     
    1210        "WKT is used for the substitution value of the geometry." 
    1311        return self.wkt 
    14  
    15     def oracle_type(self): 
    16         """ 
    17         The parameter type is a CLOB because no string (VARCHAR2) greater 
    18         than 4000 characters will be accepted through the Oracle database 
    19         API and/or SQL*Plus. 
    20         """ 
    21         return CLOB 
  • django/branches/gis/django/contrib/gis/db/backend/oracle/field.py

    r6919 r7104  
    1 import re 
    2 from types import StringType, UnicodeType 
    31from django.db import connection 
    42from django.db.backends.util import truncate_name 
    53from django.db.models.fields import Field # Django base Field class 
    6 from django.contrib.gis.geos import GEOSGeometry 
    7 from django.contrib.gis.db.backend.util import GeoFieldSQL 
    8 from django.contrib.gis.db.backend.oracle.adaptor import OracleSpatialAdaptor 
    9 from django.contrib.gis.db.backend.oracle.query import ORACLE_SPATIAL_TERMS, DISTANCE_FUNCTIONS, TRANSFORM 
     4from django.contrib.gis.db.backend.util import gqn 
     5from django.contrib.gis.db.backend.oracle.query import TRANSFORM 
    106 
    117# Quotename & geographic quotename, respectively. 
    128qn = connection.ops.quote_name 
    13 def gqn(value): 
    14     if isinstance(value, UnicodeType): value = value.encode('ascii') 
    15     return "'%s'" % value 
    169 
    1710class OracleSpatialField(Field): 
     
    9689        return 'MDSYS.SDO_GEOMETRY' 
    9790         
    98     def get_db_prep_lookup(self, lookup_type, value): 
    99         """ 
    100         Returns field's value prepared for database lookup, accepts WKT and  
    101         GEOS Geometries for the value. 
    102         """ 
    103         if lookup_type in ORACLE_SPATIAL_TERMS: 
    104             # special case for isnull lookup 
    105             if lookup_type == 'isnull': return GeoFieldSQL([], []) 
    106  
    107             # Get the geometry with SRID; defaults SRID to that 
    108             # of the field if it is None 
    109             geom = self.get_geometry(value) 
    110              
    111             # The adaptor will be used by psycopg2 for quoting the WKT. 
    112             adapt = OracleSpatialAdaptor(geom) 
    113  
    114             if geom.srid != self._srid: 
    115                 # Adding the necessary string substitutions and parameters 
    116                 # to perform a geometry transformation. 
    117                 where = ['%s(SDO_GEOMETRY(%%s, %s), %%s)' % (TRANSFORM, geom.srid)] 
    118                 params = [adapt, self._srid] 
    119             else: 
    120                 where = ['SDO_GEOMETRY(%%s, %s)' % geom.srid] 
    121                 params = [adapt] 
    122  
    123             if isinstance(value, tuple): 
    124                 if lookup_type in DISTANCE_FUNCTIONS or lookup_type == 'dwithin': 
    125                     # Getting the distance parameter in the units of the field 
    126                     where += [self.get_distance(value[1])] 
    127                 elif lookup_type == 'relate': 
    128                     # No extra where parameters for SDO_RELATE queries. 
    129                     pass 
    130                 else: 
    131                     where += map(gqn, value[1:]) 
    132             return GeoFieldSQL(where, params) 
    133         else: 
    134             raise TypeError("Field has invalid lookup: %s" % lookup_type) 
    135  
    136     def get_db_prep_save(self, value): 
    137         "Prepares the value for saving in the database." 
    138         if not bool(value): 
    139             # Return an empty string for NULL -- but this doesn't work yet. 
    140             return '' 
    141         if isinstance(value, GEOSGeometry): 
    142             return OracleSpatialAdaptor(value) 
    143         else: 
    144             raise TypeError('Geometry Proxy should only return GEOSGeometry objects.') 
    145  
    14691    def get_placeholder(self, value): 
    14792        """ 
     
    15095        SDO_CS.TRANSFORM() function call. 
    15196        """ 
    152         if isinstance(value, GEOSGeometry) and value.srid != self._srid: 
     97        if value is None: 
     98            return '%s' 
     99        elif value.srid != self._srid: 
    153100            # Adding Transform() to the SQL placeholder. 
    154101            return '%s(SDO_GEOMETRY(%%s, %s), %s)' % (TRANSFORM, value.srid, self._srid) 
    155         elif value is None: 
    156             return '%s' 
    157102        else: 
    158103            return 'SDO_GEOMETRY(%%s, %s)' % self._srid 
  • django/branches/gis/django/contrib/gis/db/backend/oracle/__init__.py

    r6886 r7104  
    1 """ 
    2  The Oracle spatial database backend module. 
    3  
    4  Please note that WKT support is broken on the XE version, and thus 
    5  this backend will not work on such platforms.  Specifically, XE lacks  
    6  support for an internal JVM, and Java libraries are required to use  
    7  the WKT constructors. 
    8 """ 
    9 from django.contrib.gis.db.backend.oracle.creation import create_spatial_db 
    10 from django.contrib.gis.db.backend.oracle.field import OracleSpatialField, gqn 
    11 from django.contrib.gis.db.backend.oracle.query import \ 
    12      get_geo_where_clause, ORACLE_SPATIAL_TERMS, \ 
    13      ASGML, DISTANCE, GEOM_SELECT, TRANSFORM, UNION 
    14  
  • django/branches/gis/django/contrib/gis/db/backend/oracle/query.py

    r6919 r7104  
    11""" 
    2  This module contains the spatial lookup types, and the get_geo_where_clause() 
     2 This module contains the spatial lookup types, and the `get_geo_where_clause` 
    33 routine for Oracle Spatial. 
     4 
     5 Please note that WKT support is broken on the XE version, and thus 
     6 this backend will not work on such platforms.  Specifically, XE lacks  
     7 support for an internal JVM, and Java libraries are required to use  
     8 the WKT constructors. 
    49""" 
    510import re 
     
    2631class SDOOperation(SpatialFunction): 
    2732    "Base class for SDO* Oracle operations." 
    28     def __init__(self, func, end_subst=") %s '%s'"): 
    29         super(SDOOperation, self).__init__(func, end_subst=end_subst, operator='=', result='TRUE') 
     33    def __init__(self, func, **kwargs): 
     34        kwargs.setdefault('operator', '=') 
     35        kwargs.setdefault('result', 'TRUE') 
     36        kwargs.setdefault('end_subst', ") %s '%s'") 
     37        super(SDOOperation, self).__init__(func, **kwargs) 
    3038 
    3139class SDODistance(SpatialFunction): 
     
    5664 
    5765# Valid distance types and substitutions 
    58 dtypes = (Decimal, Distance, float, int
     66dtypes = (Decimal, Distance, float, int, long
    5967DISTANCE_FUNCTIONS = { 
    6068    'distance_gt' : (SDODistance('>'), dtypes), 
     
    6270    'distance_lt' : (SDODistance('<'), dtypes), 
    6371    'distance_lte' : (SDODistance('<='), dtypes), 
     72    'dwithin' : (SDOOperation('SDO_WITHIN_DISTANCE',  
     73                              beg_subst="%s(%s, %%s, 'distance=%%s'"), dtypes), 
    6474    } 
    6575 
     
    6979    'covers' : SDOOperation('SDO_COVERS'), 
    7080    'disjoint' : SDOGeomRelate('DISJOINT'), 
    71     'dwithin' : (SDOOperation('SDO_WITHIN_DISTANCE', end_subst=", %%s, 'distance=%%s') %s '%s'"), dtypes), 
    7281    'intersects' : SDOOperation('SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()? 
    7382    'equals' : SDOOperation('SDO_EQUAL'), 
     
    9099 
    91100#### The `get_geo_where_clause` function for Oracle #### 
    92 def get_geo_where_clause(lookup_type, table_prefix, field_name, value): 
     101def get_geo_where_clause(lookup_type, table_prefix, field, value): 
    93102    "Returns the SQL WHERE clause for use in Oracle spatial SQL construction." 
    94103    # Getting the quoted table name as `geo_col`. 
    95     geo_col = '%s.%s' % (qn(table_prefix), qn(field_name)) 
     104    geo_col = '%s.%s' % (qn(table_prefix), qn(field.column)) 
    96105 
    97106    # See if a Oracle Geometry function matches the lookup type next 
     
    123132                return sdo_op.as_sql(geo_col) 
    124133        else: 
    125             # Lookup info is a SDOOperation instance, whos `as_sql` method returns 
     134            # Lookup info is a SDOOperation instance, whose `as_sql` method returns 
    126135            # the SQL necessary for the geometry function call. For example:   
    127136            #  SDO_CONTAINS("geoapp_country"."poly", SDO_GEOMTRY('POINT(5 23)', 4326)) = 'TRUE'