Commit 28308078 authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #22603 -- Reorganized classes in django.db.backends.

parent 737d2492
Loading
Loading
Loading
Loading
+0 −0

Empty file added.

+82 −0
Original line number Diff line number Diff line
from functools import partial


class BaseSpatialFeatures(object):
    gis_enabled = True

    # Does the database contain a SpatialRefSys model to store SRID information?
    has_spatialrefsys_table = True

    # Does the backend support the django.contrib.gis.utils.add_srs_entry() utility?
    supports_add_srs_entry = True
    # Does the backend introspect GeometryField to its subtypes?
    supports_geometry_field_introspection = True

    # Reference implementation of 3D functions is:
    # http://postgis.net/docs/PostGIS_Special_Functions_Index.html#PostGIS_3D_Functions
    supports_3d_functions = False
    # Does the database support SRID transform operations?
    supports_transform = True
    # Do geometric relationship operations operate on real shapes (or only on bounding boxes)?
    supports_real_shape_operations = True
    # Can geometry fields be null?
    supports_null_geometries = True
    # Can the `distance` GeoQuerySet method be applied on geodetic coordinate systems?
    supports_distance_geodetic = True
    # Is the database able to count vertices on polygons (with `num_points`)?
    supports_num_points_poly = True

    # The following properties indicate if the database backend support
    # certain lookups (dwithin, left and right, relate, ...)
    supports_distances_lookups = True
    supports_left_right_lookups = False

    @property
    def supports_bbcontains_lookup(self):
        return 'bbcontains' in self.connection.ops.gis_operators

    @property
    def supports_contained_lookup(self):
        return 'contained' in self.connection.ops.gis_operators

    @property
    def supports_dwithin_lookup(self):
        return 'dwithin' in self.connection.ops.gis_operators

    @property
    def supports_relate_lookup(self):
        return 'relate' in self.connection.ops.gis_operators

    # For each of those methods, the class will have a property named
    # `has_<name>_method` (defined in __init__) which accesses connection.ops
    # to determine GIS method availability.
    geoqueryset_methods = (
        'area', 'centroid', 'difference', 'distance', 'distance_spheroid',
        'envelope', 'force_rhr', 'geohash', 'gml', 'intersection', 'kml',
        'length', 'num_geom', 'perimeter', 'point_on_surface', 'reverse',
        'scale', 'snap_to_grid', 'svg', 'sym_difference', 'transform',
        'translate', 'union', 'unionagg',
    )

    # Specifies whether the Collect and Extent aggregates are supported by the database
    @property
    def supports_collect_aggr(self):
        return 'Collect' in self.connection.ops.valid_aggregates

    @property
    def supports_extent_aggr(self):
        return 'Extent' in self.connection.ops.valid_aggregates

    @property
    def supports_make_line_aggr(self):
        return 'MakeLine' in self.connection.ops.valid_aggregates

    def __init__(self, *args):
        super(BaseSpatialFeatures, self).__init__(*args)
        for method in self.geoqueryset_methods:
            # Add dynamically properties for each GQS method, e.g. has_force_rhr_method, etc.
            setattr(self.__class__, 'has_%s_method' % method,
                    property(partial(BaseSpatialFeatures.has_ops_method, method=method)))

    def has_ops_method(self, method):
        return getattr(self.connection.ops, method, False)
+0 −202
Original line number Diff line number Diff line
"""
Base/mixin classes for the spatial backend database operations and the
`<Backend>SpatialRefSys` model.
"""
from functools import partial
import re

from django.contrib.gis import gdal
@@ -10,203 +5,6 @@ from django.utils import six
from django.utils.encoding import python_2_unicode_compatible


class BaseSpatialFeatures(object):
    gis_enabled = True

    # Does the database contain a SpatialRefSys model to store SRID information?
    has_spatialrefsys_table = True

    # Does the backend support the django.contrib.gis.utils.add_srs_entry() utility?
    supports_add_srs_entry = True
    # Does the backend introspect GeometryField to its subtypes?
    supports_geometry_field_introspection = True

    # Reference implementation of 3D functions is:
    # http://postgis.net/docs/PostGIS_Special_Functions_Index.html#PostGIS_3D_Functions
    supports_3d_functions = False
    # Does the database support SRID transform operations?
    supports_transform = True
    # Do geometric relationship operations operate on real shapes (or only on bounding boxes)?
    supports_real_shape_operations = True
    # Can geometry fields be null?
    supports_null_geometries = True
    # Can the `distance` GeoQuerySet method be applied on geodetic coordinate systems?
    supports_distance_geodetic = True
    # Is the database able to count vertices on polygons (with `num_points`)?
    supports_num_points_poly = True

    # The following properties indicate if the database backend support
    # certain lookups (dwithin, left and right, relate, ...)
    supports_distances_lookups = True
    supports_left_right_lookups = False

    @property
    def supports_bbcontains_lookup(self):
        return 'bbcontains' in self.connection.ops.gis_operators

    @property
    def supports_contained_lookup(self):
        return 'contained' in self.connection.ops.gis_operators

    @property
    def supports_dwithin_lookup(self):
        return 'dwithin' in self.connection.ops.gis_operators

    @property
    def supports_relate_lookup(self):
        return 'relate' in self.connection.ops.gis_operators

    # For each of those methods, the class will have a property named
    # `has_<name>_method` (defined in __init__) which accesses connection.ops
    # to determine GIS method availability.
    geoqueryset_methods = (
        'area', 'centroid', 'difference', 'distance', 'distance_spheroid',
        'envelope', 'force_rhr', 'geohash', 'gml', 'intersection', 'kml',
        'length', 'num_geom', 'perimeter', 'point_on_surface', 'reverse',
        'scale', 'snap_to_grid', 'svg', 'sym_difference', 'transform',
        'translate', 'union', 'unionagg',
    )

    # Specifies whether the Collect and Extent aggregates are supported by the database
    @property
    def supports_collect_aggr(self):
        return 'Collect' in self.connection.ops.valid_aggregates

    @property
    def supports_extent_aggr(self):
        return 'Extent' in self.connection.ops.valid_aggregates

    @property
    def supports_make_line_aggr(self):
        return 'MakeLine' in self.connection.ops.valid_aggregates

    def __init__(self, *args):
        super(BaseSpatialFeatures, self).__init__(*args)
        for method in self.geoqueryset_methods:
            # Add dynamically properties for each GQS method, e.g. has_force_rhr_method, etc.
            setattr(self.__class__, 'has_%s_method' % method,
                    property(partial(BaseSpatialFeatures.has_ops_method, method=method)))

    def has_ops_method(self, method):
        return getattr(self.connection.ops, method, False)


class BaseSpatialOperations(object):
    """
    This module holds the base `BaseSpatialBackend` object, which is
    instantiated by each spatial database backend with the features
    it has.
    """
    truncate_params = {}

    # Quick booleans for the type of this spatial backend, and
    # an attribute for the spatial database version tuple (if applicable)
    postgis = False
    spatialite = False
    mysql = False
    oracle = False
    spatial_version = None

    # How the geometry column should be selected.
    select = None

    # Does the spatial database have a geometry or geography type?
    geography = False
    geometry = False

    area = False
    centroid = False
    difference = False
    distance = False
    distance_sphere = False
    distance_spheroid = False
    envelope = False
    force_rhr = False
    mem_size = False
    bounding_circle = False
    num_geom = False
    num_points = False
    perimeter = False
    perimeter3d = False
    point_on_surface = False
    polygonize = False
    reverse = False
    scale = False
    snap_to_grid = False
    sym_difference = False
    transform = False
    translate = False
    union = False

    # Aggregates
    collect = False
    extent = False
    extent3d = False
    make_line = False
    unionagg = False

    # Serialization
    geohash = False
    geojson = False
    gml = False
    kml = False
    svg = False

    # Constructors
    from_text = False
    from_wkb = False

    # Default conversion functions for aggregates; will be overridden if implemented
    # for the spatial backend.
    def convert_extent(self, box, srid):
        raise NotImplementedError('Aggregate extent not implemented for this spatial backend.')

    def convert_extent3d(self, box, srid):
        raise NotImplementedError('Aggregate 3D extent not implemented for this spatial backend.')

    def convert_geom(self, geom_val, geom_field):
        raise NotImplementedError('Aggregate method not implemented for this spatial backend.')

    # For quoting column values, rather than columns.
    def geo_quote_name(self, name):
        return "'%s'" % name

    # GeometryField operations
    def geo_db_type(self, f):
        """
        Returns the database column type for the geometry field on
        the spatial backend.
        """
        raise NotImplementedError('subclasses of BaseSpatialOperations must provide a geo_db_type() method')

    def get_distance(self, f, value, lookup_type):
        """
        Returns the distance parameters for the given geometry field,
        lookup value, and lookup type.
        """
        raise NotImplementedError('Distance operations not available on this spatial backend.')

    def get_geom_placeholder(self, f, value, compiler):
        """
        Returns the placeholder for the given geometry field with the given
        value.  Depending on the spatial backend, the placeholder may contain a
        stored procedure call to the transformation function of the spatial
        backend.
        """
        raise NotImplementedError('subclasses of BaseSpatialOperations must provide a geo_db_placeholder() method')

    # Spatial SQL Construction
    def spatial_aggregate_sql(self, agg):
        raise NotImplementedError('Aggregate support not implemented for this spatial backend.')

    # Routines for getting the OGC-compliant models.
    def geometry_columns(self):
        raise NotImplementedError('subclasses of BaseSpatialOperations must a provide geometry_columns() method')

    def spatial_ref_sys(self):
        raise NotImplementedError('subclasses of BaseSpatialOperations must a provide spatial_ref_sys() method')


@python_2_unicode_compatible
class SpatialRefSysMixin(object):
    """
+114 −0
Original line number Diff line number Diff line
class BaseSpatialOperations(object):
    """
    This module holds the base `BaseSpatialBackend` object, which is
    instantiated by each spatial database backend with the features
    it has.
    """
    truncate_params = {}

    # Quick booleans for the type of this spatial backend, and
    # an attribute for the spatial database version tuple (if applicable)
    postgis = False
    spatialite = False
    mysql = False
    oracle = False
    spatial_version = None

    # How the geometry column should be selected.
    select = None

    # Does the spatial database have a geometry or geography type?
    geography = False
    geometry = False

    area = False
    centroid = False
    difference = False
    distance = False
    distance_sphere = False
    distance_spheroid = False
    envelope = False
    force_rhr = False
    mem_size = False
    bounding_circle = False
    num_geom = False
    num_points = False
    perimeter = False
    perimeter3d = False
    point_on_surface = False
    polygonize = False
    reverse = False
    scale = False
    snap_to_grid = False
    sym_difference = False
    transform = False
    translate = False
    union = False

    # Aggregates
    collect = False
    extent = False
    extent3d = False
    make_line = False
    unionagg = False

    # Serialization
    geohash = False
    geojson = False
    gml = False
    kml = False
    svg = False

    # Constructors
    from_text = False
    from_wkb = False

    # Default conversion functions for aggregates; will be overridden if implemented
    # for the spatial backend.
    def convert_extent(self, box, srid):
        raise NotImplementedError('Aggregate extent not implemented for this spatial backend.')

    def convert_extent3d(self, box, srid):
        raise NotImplementedError('Aggregate 3D extent not implemented for this spatial backend.')

    def convert_geom(self, geom_val, geom_field):
        raise NotImplementedError('Aggregate method not implemented for this spatial backend.')

    # For quoting column values, rather than columns.
    def geo_quote_name(self, name):
        return "'%s'" % name

    # GeometryField operations
    def geo_db_type(self, f):
        """
        Returns the database column type for the geometry field on
        the spatial backend.
        """
        raise NotImplementedError('subclasses of BaseSpatialOperations must provide a geo_db_type() method')

    def get_distance(self, f, value, lookup_type):
        """
        Returns the distance parameters for the given geometry field,
        lookup value, and lookup type.
        """
        raise NotImplementedError('Distance operations not available on this spatial backend.')

    def get_geom_placeholder(self, f, value, compiler):
        """
        Returns the placeholder for the given geometry field with the given
        value.  Depending on the spatial backend, the placeholder may contain a
        stored procedure call to the transformation function of the spatial
        backend.
        """
        raise NotImplementedError('subclasses of BaseSpatialOperations must provide a geo_db_placeholder() method')

    # Spatial SQL Construction
    def spatial_aggregate_sql(self, agg):
        raise NotImplementedError('Aggregate support not implemented for this spatial backend.')

    # Routines for getting the OGC-compliant models.
    def geometry_columns(self):
        raise NotImplementedError('subclasses of BaseSpatialOperations must a provide geometry_columns() method')

    def spatial_ref_sys(self):
        raise NotImplementedError('subclasses of BaseSpatialOperations must a provide spatial_ref_sys() method')
Loading