1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-24 15:29:36 +02:00

feat: implement background geocoding for adventure locations on save

This commit is contained in:
Sean Morley 2025-05-29 18:17:15 -04:00
parent 9d69935f22
commit 4e8024051c

View file

@ -5,6 +5,7 @@ import uuid
from django.db import models from django.db import models
from django.utils.deconstruct import deconstructible from django.utils.deconstruct import deconstructible
from adventures.managers import AdventureManager from adventures.managers import AdventureManager
import threading
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.forms import ValidationError from django.forms import ValidationError
@ -13,6 +14,42 @@ from worldtravel.models import City, Country, Region, VisitedCity, VisitedRegion
from adventures.geocoding import reverse_geocode from adventures.geocoding import reverse_geocode
from django.utils import timezone from django.utils import timezone
def background_geocode_and_assign(adventure_id: str):
try:
adventure = Adventure.objects.get(id=adventure_id)
if not (adventure.latitude and adventure.longitude):
return
from adventures.geocoding import reverse_geocode # or wherever you defined it
is_visited = adventure.is_visited_status()
result = reverse_geocode(adventure.latitude, adventure.longitude, adventure.user_id)
if 'region_id' in result:
region = Region.objects.filter(id=result['region_id']).first()
if region:
adventure.region = region
if is_visited:
VisitedRegion.objects.get_or_create(user_id=adventure.user_id, region=region)
if 'city_id' in result:
city = City.objects.filter(id=result['city_id']).first()
if city:
adventure.city = city
if is_visited:
VisitedCity.objects.get_or_create(user_id=adventure.user_id, city=city)
if 'country_id' in result:
country = Country.objects.filter(country_code=result['country_id']).first()
if country:
adventure.country = country
# Save updated location info
adventure.save(update_fields=["region", "city", "country"])
except Exception as e:
# Optional: log or print the error
print(f"[Adventure Geocode Thread] Error processing {adventure_id}: {e}")
def validate_file_extension(value): def validate_file_extension(value):
import os import os
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@ -571,51 +608,25 @@ class Adventure(models.Model):
if self.user_id != self.category.user_id: if self.user_id != self.category.user_id:
raise ValidationError('Adventures must be associated with categories owned by the same user. Category owner: ' + self.category.user_id.username + ' Adventure owner: ' + self.user_id.username) raise ValidationError('Adventures must be associated with categories owned by the same user. Category owner: ' + self.category.user_id.username + ' Adventure owner: ' + self.user_id.username)
def save(self, force_insert: bool = False, force_update: bool = False, using: str | None = None, update_fields: Iterable[str] | None = None) -> None: def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
"""
Saves the current instance. If the instance is being inserted for the first time, it will be created in the database.
If it already exists, it will be updated.
"""
if force_insert and force_update: if force_insert and force_update:
raise ValueError("Cannot force both insert and updating in model saving.") raise ValueError("Cannot force both insert and updating in model saving.")
if not self.category: if not self.category:
category, created = Category.objects.get_or_create( category, _ = Category.objects.get_or_create(
user_id=self.user_id, user_id=self.user_id,
name='general', name='general',
defaults={ defaults={'display_name': 'General', 'icon': '🌍'}
'display_name': 'General',
'icon': '🌍'
}
) )
self.category = category self.category = category
if self.latitude and self.longitude: # First save the adventure quickly
is_visited = self.is_visited_status() result = super().save(force_insert, force_update, using, update_fields)
reverse_geocode_result = reverse_geocode(self.latitude, self.longitude, self.user_id)
if 'region_id' in reverse_geocode_result:
region = Region.objects.filter(id=reverse_geocode_result['region_id']).first()
if region:
self.region = region
if is_visited:
visited_region, created = VisitedRegion.objects.get_or_create(
user_id=self.user_id,
region=region
)
if 'city_id' in reverse_geocode_result:
city = City.objects.filter(id=reverse_geocode_result['city_id']).first()
if city:
self.city = city
if is_visited:
visited_city, created = VisitedCity.objects.get_or_create(
user_id=self.user_id,
city=city
)
if 'country_id' in reverse_geocode_result:
country = Country.objects.filter(country_code=reverse_geocode_result['country_id']).first()
if country:
self.country = country
return super().save(force_insert, force_update, using, update_fields) # Then fire off a thread to geocode + update region/city/country
if self.latitude and self.longitude:
threading.Thread(target=background_geocode_and_assign, args=(str(self.id),)).start()
return result
def __str__(self): def __str__(self):
return self.name return self.name