1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- """
- The SpatialProxy object allows for lazy-geometries and lazy-rasters. The proxy
- uses Python descriptors for instantiating and setting Geometry or Raster
- objects corresponding to geographic model fields.
-
- Thanks to Robert Coup for providing this functionality (see #4322).
- """
- from django.db.models.query_utils import DeferredAttribute
-
-
- class SpatialProxy(DeferredAttribute):
- def __init__(self, klass, field, load_func=None):
- """
- Initialize on the given Geometry or Raster class (not an instance)
- and the corresponding field.
- """
- self._field = field
- self._klass = klass
- self._load_func = load_func or klass
- super().__init__(field.attname)
-
- def __get__(self, instance, cls=None):
- """
- Retrieve the geometry or raster, initializing it using the
- corresponding class specified during initialization and the value of
- the field. Currently, GEOS or OGR geometries as well as GDALRasters are
- supported.
- """
- if instance is None:
- # Accessed on a class, not an instance
- return self
-
- # Getting the value of the field.
- try:
- geo_value = instance.__dict__[self._field.attname]
- except KeyError:
- geo_value = super().__get__(instance, cls)
-
- if isinstance(geo_value, self._klass):
- geo_obj = geo_value
- elif (geo_value is None) or (geo_value == ''):
- geo_obj = None
- else:
- # Otherwise, a geometry or raster object is built using the field's
- # contents, and the model's corresponding attribute is set.
- geo_obj = self._load_func(geo_value)
- setattr(instance, self._field.attname, geo_obj)
- return geo_obj
-
- def __set__(self, instance, value):
- """
- Retrieve the proxied geometry or raster with the corresponding class
- specified during initialization.
-
- To set geometries, use values of None, HEXEWKB, or WKT.
- To set rasters, use JSON or dict values.
- """
- # The geographic type of the field.
- gtype = self._field.geom_type
-
- if gtype == 'RASTER' and (value is None or isinstance(value, (str, dict, self._klass))):
- # For raster fields, assure input is None or a string, dict, or
- # raster instance.
- pass
- elif isinstance(value, self._klass):
- # The geometry type must match that of the field -- unless the
- # general GeometryField is used.
- if value.srid is None:
- # Assigning the field SRID if the geometry has no SRID.
- value.srid = self._field.srid
- elif value is None or isinstance(value, (str, memoryview)):
- # Set geometries with None, WKT, HEX, or WKB
- pass
- else:
- raise TypeError('Cannot set %s SpatialProxy (%s) with value of type: %s' % (
- instance.__class__.__name__, gtype, type(value)))
-
- # Setting the objects dictionary with the value, and returning.
- instance.__dict__[self._field.attname] = value
- return value
|