You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

conversion.py 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """
  2. This module holds simple classes to convert geospatial values from the
  3. database.
  4. """
  5. from decimal import Decimal
  6. from django.contrib.gis.measure import Area, Distance
  7. from django.db import models
  8. class AreaField(models.FloatField):
  9. "Wrapper for Area values."
  10. def __init__(self, geo_field):
  11. super().__init__()
  12. self.geo_field = geo_field
  13. def get_prep_value(self, value):
  14. if not isinstance(value, Area):
  15. raise ValueError('AreaField only accepts Area measurement objects.')
  16. return value
  17. def get_db_prep_value(self, value, connection, prepared=False):
  18. if value is None:
  19. return
  20. area_att = connection.ops.get_area_att_for_field(self.geo_field)
  21. return getattr(value, area_att) if area_att else value
  22. def from_db_value(self, value, expression, connection):
  23. if value is None:
  24. return
  25. # If the database returns a Decimal, convert it to a float as expected
  26. # by the Python geometric objects.
  27. if isinstance(value, Decimal):
  28. value = float(value)
  29. # If the units are known, convert value into area measure.
  30. area_att = connection.ops.get_area_att_for_field(self.geo_field)
  31. return Area(**{area_att: value}) if area_att else value
  32. def get_internal_type(self):
  33. return 'AreaField'
  34. class DistanceField(models.FloatField):
  35. "Wrapper for Distance values."
  36. def __init__(self, geo_field):
  37. super().__init__()
  38. self.geo_field = geo_field
  39. def get_prep_value(self, value):
  40. if isinstance(value, Distance):
  41. return value
  42. return super().get_prep_value(value)
  43. def get_db_prep_value(self, value, connection, prepared=False):
  44. if not isinstance(value, Distance):
  45. return value
  46. distance_att = connection.ops.get_distance_att_for_field(self.geo_field)
  47. if not distance_att:
  48. raise ValueError('Distance measure is supplied, but units are unknown for result.')
  49. return getattr(value, distance_att)
  50. def from_db_value(self, value, expression, connection):
  51. if value is None:
  52. return
  53. distance_att = connection.ops.get_distance_att_for_field(self.geo_field)
  54. return Distance(**{distance_att: value}) if distance_att else value
  55. def get_internal_type(self):
  56. return 'DistanceField'