| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- """
- 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._klass = klass
- self._load_func = load_func or klass
- super().__init__(field)
- 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, ensure 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
|