initial geodjango implementation

This commit is contained in:
pacnpal
2024-11-05 04:10:47 +00:00
parent f1977cde3f
commit 9cd7ee94a5
22 changed files with 768 additions and 229 deletions

View File

@@ -2,7 +2,6 @@ from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from django.contrib.contenttypes.fields import GenericRelation
from django.core.validators import MinValueValidator, MaxValueValidator
from django.core.exceptions import ValidationError
from decimal import Decimal, ROUND_DOWN, InvalidOperation
from simple_history.models import HistoricalRecords
@@ -10,48 +9,7 @@ from simple_history.models import HistoricalRecords
from companies.models import Company
from media.models import Photo
from history_tracking.models import HistoricalModel
def normalize_coordinate(value, max_digits, decimal_places):
"""Normalize coordinate to have at most max_digits total digits and decimal_places decimal places"""
try:
if value is None:
return None
# Convert to Decimal for precise handling
value = Decimal(str(value))
# Round to specified decimal places
value = Decimal(
value.quantize(Decimal("0." + "0" * decimal_places), rounding=ROUND_DOWN)
)
return value
except (TypeError, ValueError, InvalidOperation):
return None
def validate_coordinate_digits(value, max_digits, decimal_places):
"""Validate total number of digits in a coordinate value"""
if value is not None:
try:
# Convert to Decimal for precise handling
value = Decimal(str(value))
# Round to exactly 6 decimal places
value = value.quantize(Decimal("0.000001"), rounding=ROUND_DOWN)
return value
except (InvalidOperation, TypeError):
raise ValidationError("Invalid coordinate value.")
return value
def validate_latitude_digits(value):
"""Validate total number of digits in latitude"""
return validate_coordinate_digits(value, 9, 6)
def validate_longitude_digits(value):
"""Validate total number of digits in longitude"""
return validate_coordinate_digits(value, 10, 6)
from location.models import Location
class Park(HistoricalModel):
@@ -71,36 +29,8 @@ class Park(HistoricalModel):
max_length=20, choices=STATUS_CHOICES, default="OPERATING"
)
# Location fields
latitude = models.DecimalField(
max_digits=9,
decimal_places=6,
null=True,
blank=True,
help_text="Latitude coordinate (-90 to 90)",
validators=[
MinValueValidator(Decimal("-90")),
MaxValueValidator(Decimal("90")),
validate_latitude_digits,
],
)
longitude = models.DecimalField(
max_digits=10,
decimal_places=6,
null=True,
blank=True,
help_text="Longitude coordinate (-180 to 180)",
validators=[
MinValueValidator(Decimal("-180")),
MaxValueValidator(Decimal("180")),
validate_longitude_digits,
],
)
street_address = models.CharField(max_length=255, blank=True)
city = models.CharField(max_length=255, blank=True)
state = models.CharField(max_length=255, blank=True)
country = models.CharField(max_length=255, blank=True)
postal_code = models.CharField(max_length=20, blank=True)
# Location fields using GenericRelation
location = GenericRelation(Location, related_query_name='park')
# Details
opening_date = models.DateField(null=True, blank=True)
@@ -138,13 +68,6 @@ class Park(HistoricalModel):
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
# Normalize coordinates before saving
if self.latitude is not None:
self.latitude = normalize_coordinate(self.latitude, 9, 6)
if self.longitude is not None:
self.longitude = normalize_coordinate(self.longitude, 10, 6)
super().save(*args, **kwargs)
def get_absolute_url(self):
@@ -152,14 +75,18 @@ class Park(HistoricalModel):
@property
def formatted_location(self):
parts = []
if self.city:
parts.append(self.city)
if self.state:
parts.append(self.state)
if self.country:
parts.append(self.country)
return ", ".join(parts)
if self.location.exists():
location = self.location.first()
return location.get_formatted_address()
return ""
@property
def coordinates(self):
"""Returns coordinates as a tuple (latitude, longitude)"""
if self.location.exists():
location = self.location.first()
return location.coordinates
return None
@classmethod
def get_by_slug(cls, slug):