| from django.db.models.sql.aggregates import * |
| from django.contrib.gis.db.models.fields import GeometryField |
| from django.contrib.gis.db.models.sql.conversion import GeomField |
| |
| class GeoAggregate(Aggregate): |
| # Default SQL template for spatial aggregates. |
| sql_template = '%(function)s(%(field)s)' |
| |
| # Conversion class, if necessary. |
| conversion_class = None |
| |
| # Flags for indicating the type of the aggregate. |
| is_extent = False |
| |
| def __init__(self, col, source=None, is_summary=False, tolerance=0.05, **extra): |
| super(GeoAggregate, self).__init__(col, source, is_summary, **extra) |
| |
| # Required by some Oracle aggregates. |
| self.tolerance = tolerance |
| |
| # Can't use geographic aggregates on non-geometry fields. |
| if not isinstance(self.source, GeometryField): |
| raise ValueError('Geospatial aggregates only allowed on geometry fields.') |
| |
| def as_sql(self, qn, connection): |
| "Return the aggregate, rendered as SQL." |
| |
| if connection.ops.oracle: |
| self.extra['tolerance'] = self.tolerance |
| |
| if hasattr(self.col, 'as_sql'): |
| field_name = self.col.as_sql(qn, connection) |
| elif isinstance(self.col, (list, tuple)): |
| field_name = '.'.join([qn(c) for c in self.col]) |
| else: |
| field_name = self.col |
| |
| sql_template, sql_function = connection.ops.spatial_aggregate_sql(self) |
| |
| params = { |
| 'function': sql_function, |
| 'field': field_name |
| } |
| params.update(self.extra) |
| |
| return sql_template % params |
| |
| class Collect(GeoAggregate): |
| pass |
| |
| class Extent(GeoAggregate): |
| is_extent = '2D' |
| |
| class Extent3D(GeoAggregate): |
| is_extent = '3D' |
| |
| class MakeLine(GeoAggregate): |
| pass |
| |
| class Union(GeoAggregate): |
| pass |