models.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import logging
  2. from typing import Dict
  3. from uuid import uuid4
  4. from django.contrib.auth import get_user_model
  5. from django.conf import settings
  6. from django.db import models
  7. from django.urls import reverse
  8. from django_extensions.db.models import TimeStampedModel
  9. from scrobbles.mixins import ScrobblableMixin
  10. logger = logging.getLogger(__name__)
  11. BNULL = {"blank": True, "null": True}
  12. User = get_user_model()
  13. class GeoLocation(ScrobblableMixin):
  14. COMPLETION_PERCENT = getattr(settings, "LOCATION_COMPLETION_PERCENT", 100)
  15. uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
  16. lat = models.FloatField()
  17. lon = models.FloatField()
  18. altitude = models.FloatField(**BNULL)
  19. class Meta:
  20. unique_together = [["lat", "lon", "altitude"]]
  21. def __str__(self):
  22. return f"{self.lat} x {self.lon}"
  23. def get_absolute_url(self):
  24. return reverse(
  25. "locations:geo_location_detail", kwargs={"slug": self.uuid}
  26. )
  27. @property
  28. def truncated_lat(self):
  29. return float(str(self.lat)[:-3])
  30. @property
  31. def truncated_lan(self):
  32. return float(str(self.lon)[:-3])
  33. @classmethod
  34. def find_or_create(cls, data_dict: Dict) -> "GeoLocation":
  35. """Given a data dict from GPSLogger, does the heavy lifting of looking up
  36. the location, creating if if doesn't exist yet.
  37. """
  38. # TODO Add constants for all these data keys
  39. if "lat" not in data_dict.keys() or "lon" not in data_dict.keys():
  40. logger.error("No lat or lon keys in data dict")
  41. return
  42. lat_int, lat_places = data_dict.get("lat", "").split(".")
  43. lon_int, lon_places = data_dict.get("lon", "").split(".")
  44. alt_int, alt_places = data_dict.get("alt", "").split(".")
  45. truncated_lat = lat_places[0:5]
  46. truncated_lon = lon_places[0:5]
  47. truncated_alt = alt_places[0:3]
  48. data_dict["lat"] = float(".".join([lat_int, truncated_lat]))
  49. data_dict["lon"] = float(".".join([lon_int, truncated_lon]))
  50. data_dict["altitude"] = float(".".join([alt_int, truncated_alt]))
  51. location = cls.objects.filter(
  52. lat=data_dict.get("lat"),
  53. lon=data_dict.get("lon"),
  54. altitude=data_dict.get("alt"),
  55. ).first()
  56. if not location:
  57. location = cls.objects.create(
  58. lat=data_dict.get("lat"),
  59. lon=data_dict.get("lon"),
  60. altitude=data_dict.get("alt"),
  61. )
  62. return location
  63. class RawGeoLocation(TimeStampedModel):
  64. user = models.ForeignKey(User, on_delete=models.CASCADE)
  65. lat = models.FloatField()
  66. lon = models.FloatField()
  67. altitude = models.FloatField(**BNULL)
  68. speed = models.FloatField(**BNULL)
  69. timestamp = models.DateTimeField(**BNULL)