Skip to content

Commit

Permalink
Added timezone field. Fix #127
Browse files Browse the repository at this point in the history
  • Loading branch information
epou committed Nov 30, 2023
1 parent a0f6721 commit ccca449
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 0 deletions.
6 changes: 6 additions & 0 deletions mosquito_alert/geo/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from django.apps import AppConfig
from timezonefinder import TimezoneFinder


class GeoConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "mosquito_alert.geo"

def ready(self):
# Initialize the TimezoneFinder object and store it as a class attribute
# due to the first load is quite slow.
self.timezone_finder = TimezoneFinder()
18 changes: 18 additions & 0 deletions mosquito_alert/geo/migrations/0003_location_timezone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.3 on 2023-11-30 17:10

from django.db import migrations
import timezone_field.fields


class Migration(migrations.Migration):
dependencies = [
("geo", "0002_alter_boundary_created_at_alter_boundary_updated_at_and_more"),
]

operations = [
migrations.AddField(
model_name="location",
name="timezone",
field=timezone_field.fields.TimeZoneField(blank=True, editable=False, null=True),
),
]
22 changes: 22 additions & 0 deletions mosquito_alert/geo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
LifecycleModelMixin,
hook,
)
from timezone_field import TimeZoneField
from treebeard.mp_tree import MP_Node

from mosquito_alert.utils.models import ParentManageableNodeMixin, TimeStampedModel
Expand Down Expand Up @@ -305,6 +306,7 @@ class LocationType(models.TextChoices):

# Attributes - Mandatory
point = models.PointField(geography=False)
timezone = TimeZoneField(null=True, blank=True, editable=False)
location_type = models.CharField(max_length=3, choices=LocationType.choices, null=True, blank=True)
# TODO: add positional_accuray (The uncertainty in meters around the latitude and longitude.)

Expand All @@ -313,12 +315,32 @@ class LocationType(models.TextChoices):
objects = LocationManager()

# Custom Properties
@property
def latitude(self):
return self.point.y

@property
def longitude(self):
return self.point.x

# Methods
@hook(AFTER_CREATE)
@hook(AFTER_UPDATE, when="point", has_changed=True)
def update_linked_boundaries(self):
self.boundaries.set(Boundary.objects.reverse_geocoding(point=self.point).all())

@hook(BEFORE_CREATE)
@hook(BEFORE_UPDATE, when="point", has_changed=True)
def _update_timezone(self):
# Access the TimezoneFinder object from the AppConfig
timezone_finder = self._meta.app_config.timezone_finder

# Set the timezone using latitude and longitude
try:
self.timezone = timezone_finder.timezone_at(lat=self.latitude, lng=self.longitude)
except Exception:
pass

# Meta and String
class Meta:
verbose_name = _("location")
Expand Down
44 changes: 44 additions & 0 deletions mosquito_alert/geo/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,12 +385,32 @@ def test_point_can_not_be_blank(self):
def test_point_srid_is_4326(self):
assert self.model._meta.get_field("point").srid == 4326

def test_timezone_can_be_null(self):
assert self.model._meta.get_field("timezone").null

def test_timezone_can_be_blank(self):
assert self.model._meta.get_field("timezone").blank

def test_timezone_is_not_editable(self):
assert not self.model._meta.get_field("timezone").editable

def test_location_type_can_be_null(self):
assert self.model._meta.get_field("location_type").null

def test_location_type_can_be_blank(self):
assert self.model._meta.get_field("location_type").blank

# properties
def test_latitude(self):
obj = self.factory_cls(point=Point(x=2.79, y=41.67, srid=4326))

obj.latitude == 41.67

def test_longitude(self):
obj = self.factory_cls(point=Point(x=2.79, y=41.67, srid=4326))

obj.latitude == 2.79

# methods
def test_update_boundaries_on_create(self, country_bl):
bbox_poly_a = (0, 0, 10, 10) # x0, y0, x1, y1
Expand Down Expand Up @@ -440,6 +460,30 @@ def test_update_boundaries_on_point_update(self, country_bl):

assert list(location_in_a.boundaries.all()) == [boundary_b]

def test_timezone_is_auto_set_on_create(self):
# Blanes
obj = self.factory_cls(point=Point(x=2.70, y=41.61, srid=4326))
assert obj.timezone == "Europe/Madrid"

def test_timezone_is_updated_on_point_change(self):
# Blanes
obj = self.factory_cls(point=Point(x=2.70, y=41.61, srid=4326))
assert obj.timezone == "Europe/Madrid"

# Paris
obj.point = Point(x=2.37, y=49.03, srid=4326)
obj.save()
assert obj.timezone == "Europe/Paris"

def test_timezone_does_not_raise_on_ETC_timezones(self):
# Middle of the ocean
obj = self.factory_cls(point=Point(x=-36.38, y=41.50, srid=4326))
assert obj.timezone == "Etc/GMT+2"

def test_timezone_is_set_to_None_if_timezone_finder_raises(self):
obj = self.factory_cls(point=Point(x=80000, y=80000, srid=4326))
assert obj.timezone is None

# meta
def test__str__with_location_type(self):
point = FuzzyPoint(srid=4326).fuzz()
Expand Down
2 changes: 2 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ geopandas==0.12.2 # https://github.com/geopandas/geopandas
tqdm==4.64.1
geopy==2.3.0 # https://github.com/geopy/geopy
anytree==2.8.0 # https://github.com/c0fec0de/anytree
timezonefinder==6.2.0 # https://github.com/jannikmi/timezonefinder

# Django
# ------------------------------------------------------------------------------
Expand All @@ -37,6 +38,7 @@ django-notifications-hq==1.8.2 # https://github.com/django-notifications/django
django-lb-health-check==1.0.1 # https://github.com/Hovercross/django-lb-health-check
django-simple-history==3.3.0 # https://github.com/jazzband/django-simple-history
django-jsonform==2.19.1 # https://github.com/bhch/django-jsonform
django-timezone-field==6.1.0 # https://github.com/mfogel/django-timezone-field/
# Django Admin
django-admin-sortable2==2.1.8 # https://github.com/jrief/django-admin-sortable2
django-nested-admin==4.0.2 # https://github.com/theatlantic/django-nested-admin
Expand Down

0 comments on commit ccca449

Please sign in to comment.