mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 08:51:09 -05:00
initial geodjango implementation
This commit is contained in:
Binary file not shown.
Binary file not shown.
124
parks/forms.py
124
parks/forms.py
@@ -5,6 +5,64 @@ from .models import Park
|
||||
|
||||
class ParkForm(forms.ModelForm):
|
||||
"""Form for creating and updating Park objects with location support"""
|
||||
# Location fields
|
||||
latitude = forms.DecimalField(
|
||||
max_digits=9,
|
||||
decimal_places=6,
|
||||
required=False,
|
||||
widget=forms.HiddenInput()
|
||||
)
|
||||
longitude = forms.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=6,
|
||||
required=False,
|
||||
widget=forms.HiddenInput()
|
||||
)
|
||||
street_address = forms.CharField(
|
||||
max_length=255,
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
)
|
||||
)
|
||||
city = forms.CharField(
|
||||
max_length=255,
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
)
|
||||
)
|
||||
state = forms.CharField(
|
||||
max_length=255,
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
)
|
||||
)
|
||||
country = forms.CharField(
|
||||
max_length=255,
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
)
|
||||
)
|
||||
postal_code = forms.CharField(
|
||||
max_length=20,
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Park
|
||||
@@ -18,6 +76,7 @@ class ParkForm(forms.ModelForm):
|
||||
"operating_season",
|
||||
"size_acres",
|
||||
"website",
|
||||
# Location fields handled separately
|
||||
"latitude",
|
||||
"longitude",
|
||||
"street_address",
|
||||
@@ -79,36 +138,21 @@ class ParkForm(forms.ModelForm):
|
||||
"placeholder": "https://example.com",
|
||||
}
|
||||
),
|
||||
# Location fields
|
||||
"latitude": forms.HiddenInput(),
|
||||
"longitude": forms.HiddenInput(),
|
||||
"street_address": forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
),
|
||||
"city": forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
),
|
||||
"state": forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
),
|
||||
"country": forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
),
|
||||
"postal_code": forms.TextInput(
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Pre-fill location fields if editing existing park
|
||||
if self.instance and self.instance.pk and self.instance.location.exists():
|
||||
location = self.instance.location.first()
|
||||
self.fields['latitude'].initial = location.latitude
|
||||
self.fields['longitude'].initial = location.longitude
|
||||
self.fields['street_address'].initial = location.street_address
|
||||
self.fields['city'].initial = location.city
|
||||
self.fields['state'].initial = location.state
|
||||
self.fields['country'].initial = location.country
|
||||
self.fields['postal_code'].initial = location.postal_code
|
||||
|
||||
def clean_latitude(self):
|
||||
latitude = self.cleaned_data.get('latitude')
|
||||
if latitude is not None:
|
||||
@@ -146,3 +190,27 @@ class ParkForm(forms.ModelForm):
|
||||
except (InvalidOperation, TypeError):
|
||||
raise forms.ValidationError("Invalid longitude value.")
|
||||
return longitude
|
||||
|
||||
def save(self, commit=True):
|
||||
park = super().save(commit=False)
|
||||
|
||||
# Prepare location data
|
||||
location_data = {
|
||||
'name': park.name,
|
||||
'location_type': 'park',
|
||||
'latitude': self.cleaned_data.get('latitude'),
|
||||
'longitude': self.cleaned_data.get('longitude'),
|
||||
'street_address': self.cleaned_data.get('street_address'),
|
||||
'city': self.cleaned_data.get('city'),
|
||||
'state': self.cleaned_data.get('state'),
|
||||
'country': self.cleaned_data.get('country'),
|
||||
'postal_code': self.cleaned_data.get('postal_code'),
|
||||
}
|
||||
|
||||
# Set location data to be saved with the park
|
||||
park.set_location(**location_data)
|
||||
|
||||
if commit:
|
||||
park.save()
|
||||
|
||||
return park
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Generated by Django 5.1.2 on 2024-11-03 19:59
|
||||
|
||||
import django.core.validators
|
||||
import parks.models
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
@@ -25,7 +24,6 @@ class Migration(migrations.Migration):
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(Decimal("-90")),
|
||||
django.core.validators.MaxValueValidator(Decimal("90")),
|
||||
parks.models.validate_latitude_digits,
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -41,7 +39,6 @@ class Migration(migrations.Migration):
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(Decimal("-180")),
|
||||
django.core.validators.MaxValueValidator(Decimal("180")),
|
||||
parks.models.validate_longitude_digits,
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -57,7 +54,6 @@ class Migration(migrations.Migration):
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(Decimal("-90")),
|
||||
django.core.validators.MaxValueValidator(Decimal("90")),
|
||||
parks.models.validate_latitude_digits,
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -73,7 +69,6 @@ class Migration(migrations.Migration):
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(Decimal("-180")),
|
||||
django.core.validators.MaxValueValidator(Decimal("180")),
|
||||
parks.models.validate_longitude_digits,
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
import history_tracking.mixins
|
||||
import parks.models
|
||||
import simple_history.models
|
||||
from decimal import Decimal
|
||||
from django.conf import settings
|
||||
@@ -57,7 +56,6 @@ class Migration(migrations.Migration):
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(Decimal("-90")),
|
||||
django.core.validators.MaxValueValidator(Decimal("90")),
|
||||
parks.models.validate_latitude_digits,
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -72,7 +70,6 @@ class Migration(migrations.Migration):
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(Decimal("-180")),
|
||||
django.core.validators.MaxValueValidator(Decimal("180")),
|
||||
parks.models.validate_longitude_digits,
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
83
parks/migrations/0009_migrate_to_location_model.py
Normal file
83
parks/migrations/0009_migrate_to_location_model.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# Generated by Django 5.1.2 on 2024-11-04 22:21
|
||||
|
||||
from django.db import migrations, transaction
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
def forwards_func(apps, schema_editor):
|
||||
"""Move park location data to Location model"""
|
||||
Park = apps.get_model("parks", "Park")
|
||||
Location = apps.get_model("location", "Location")
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
# Get content type for Park model
|
||||
park_content_type = ContentType.objects.db_manager(db_alias).get(
|
||||
app_label='parks',
|
||||
model='park'
|
||||
)
|
||||
|
||||
# Move location data for each park
|
||||
with transaction.atomic():
|
||||
for park in Park.objects.using(db_alias).all():
|
||||
# Only create Location if park has coordinate data
|
||||
if park.latitude is not None and park.longitude is not None:
|
||||
Location.objects.using(db_alias).create(
|
||||
content_type=park_content_type,
|
||||
object_id=park.id,
|
||||
name=park.name,
|
||||
location_type='park',
|
||||
latitude=park.latitude,
|
||||
longitude=park.longitude,
|
||||
street_address=park.street_address,
|
||||
city=park.city,
|
||||
state=park.state,
|
||||
country=park.country,
|
||||
postal_code=park.postal_code
|
||||
)
|
||||
|
||||
def reverse_func(apps, schema_editor):
|
||||
"""Move location data back to Park model"""
|
||||
Park = apps.get_model("parks", "Park")
|
||||
Location = apps.get_model("location", "Location")
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
# Get content type for Park model
|
||||
park_content_type = ContentType.objects.db_manager(db_alias).get(
|
||||
app_label='parks',
|
||||
model='park'
|
||||
)
|
||||
|
||||
# Move location data back to each park
|
||||
with transaction.atomic():
|
||||
locations = Location.objects.using(db_alias).filter(
|
||||
content_type=park_content_type
|
||||
)
|
||||
for location in locations:
|
||||
try:
|
||||
park = Park.objects.using(db_alias).get(id=location.object_id)
|
||||
park.latitude = location.latitude
|
||||
park.longitude = location.longitude
|
||||
park.street_address = location.street_address
|
||||
park.city = location.city
|
||||
park.state = location.state
|
||||
park.country = location.country
|
||||
park.postal_code = location.postal_code
|
||||
park.save()
|
||||
except Park.DoesNotExist:
|
||||
continue
|
||||
|
||||
# Delete all park locations
|
||||
locations.delete()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('parks', '0008_historicalpark_historicalparkarea'),
|
||||
('location', '0005_convert_coordinates_to_points'),
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards_func, reverse_func, atomic=True),
|
||||
]
|
||||
69
parks/migrations/0010_remove_legacy_location_fields.py
Normal file
69
parks/migrations/0010_remove_legacy_location_fields.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# Generated by Django 5.1.2 on 2024-11-04 22:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("parks", "0009_migrate_to_location_model"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="latitude",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="longitude",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="street_address",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="city",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="state",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="country",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="historicalpark",
|
||||
name="postal_code",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="latitude",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="longitude",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="street_address",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="city",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="state",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="country",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="park",
|
||||
name="postal_code",
|
||||
),
|
||||
]
|
||||
103
parks/models.py
103
parks/models.py
@@ -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):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from decimal import Decimal, ROUND_DOWN
|
||||
from decimal import Decimal, ROUND_DOWN, InvalidOperation
|
||||
from django.views.generic import DetailView, ListView, CreateView, UpdateView
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
@@ -16,6 +16,7 @@ from core.views import SlugRedirectMixin
|
||||
from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin
|
||||
from moderation.models import EditSubmission
|
||||
from media.models import Photo
|
||||
from location.models import Location
|
||||
|
||||
|
||||
def location_search(request):
|
||||
@@ -101,7 +102,7 @@ class ParkListView(ListView):
|
||||
context_object_name = "parks"
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Park.objects.select_related("owner").prefetch_related("photos")
|
||||
queryset = Park.objects.select_related("owner").prefetch_related("photos", "location")
|
||||
|
||||
search = self.request.GET.get("search", "").strip()
|
||||
country = self.request.GET.get("country", "").strip()
|
||||
@@ -111,25 +112,25 @@ class ParkListView(ListView):
|
||||
|
||||
if search:
|
||||
queryset = queryset.filter(
|
||||
Q(name__icontains=search)
|
||||
| Q(city__icontains=search)
|
||||
| Q(state__icontains=search)
|
||||
| Q(country__icontains=search)
|
||||
Q(name__icontains=search) |
|
||||
Q(location__city__icontains=search) |
|
||||
Q(location__state__icontains=search) |
|
||||
Q(location__country__icontains=search)
|
||||
)
|
||||
|
||||
if country:
|
||||
queryset = queryset.filter(country__icontains=country)
|
||||
queryset = queryset.filter(location__country__icontains=country)
|
||||
|
||||
if region:
|
||||
queryset = queryset.filter(state__icontains=region)
|
||||
queryset = queryset.filter(location__state__icontains=region)
|
||||
|
||||
if city:
|
||||
queryset = queryset.filter(city__icontains=city)
|
||||
queryset = queryset.filter(location__city__icontains=city)
|
||||
|
||||
if statuses:
|
||||
queryset = queryset.filter(status__in=statuses)
|
||||
|
||||
return queryset
|
||||
return queryset.distinct()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
@@ -173,7 +174,8 @@ class ParkDetailView(
|
||||
'rides',
|
||||
'rides__manufacturer',
|
||||
'photos',
|
||||
'areas'
|
||||
'areas',
|
||||
'location'
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -242,6 +244,22 @@ class ParkCreateView(LoginRequiredMixin, CreateView):
|
||||
submission.handled_by = self.request.user
|
||||
submission.save()
|
||||
|
||||
# Create Location record
|
||||
if form.cleaned_data.get("latitude") and form.cleaned_data.get("longitude"):
|
||||
Location.objects.create(
|
||||
content_type=ContentType.objects.get_for_model(Park),
|
||||
object_id=self.object.id,
|
||||
name=self.object.name,
|
||||
location_type='park',
|
||||
latitude=form.cleaned_data["latitude"],
|
||||
longitude=form.cleaned_data["longitude"],
|
||||
street_address=form.cleaned_data.get("street_address", ""),
|
||||
city=form.cleaned_data.get("city", ""),
|
||||
state=form.cleaned_data.get("state", ""),
|
||||
country=form.cleaned_data.get("country", ""),
|
||||
postal_code=form.cleaned_data.get("postal_code", "")
|
||||
)
|
||||
|
||||
# Handle photo uploads
|
||||
photos = self.request.FILES.getlist("photos")
|
||||
for photo_file in photos:
|
||||
@@ -349,6 +367,31 @@ class ParkUpdateView(LoginRequiredMixin, UpdateView):
|
||||
submission.handled_by = self.request.user
|
||||
submission.save()
|
||||
|
||||
# Update or create Location record
|
||||
location_data = {
|
||||
'name': self.object.name,
|
||||
'location_type': 'park',
|
||||
'latitude': form.cleaned_data.get("latitude"),
|
||||
'longitude': form.cleaned_data.get("longitude"),
|
||||
'street_address': form.cleaned_data.get("street_address", ""),
|
||||
'city': form.cleaned_data.get("city", ""),
|
||||
'state': form.cleaned_data.get("state", ""),
|
||||
'country': form.cleaned_data.get("country", ""),
|
||||
'postal_code': form.cleaned_data.get("postal_code", "")
|
||||
}
|
||||
|
||||
if self.object.location.exists():
|
||||
location = self.object.location.first()
|
||||
for key, value in location_data.items():
|
||||
setattr(location, key, value)
|
||||
location.save()
|
||||
else:
|
||||
Location.objects.create(
|
||||
content_type=ContentType.objects.get_for_model(Park),
|
||||
object_id=self.object.id,
|
||||
**location_data
|
||||
)
|
||||
|
||||
# Handle photo uploads
|
||||
photos = self.request.FILES.getlist("photos")
|
||||
uploaded_count = 0
|
||||
|
||||
Reference in New Issue
Block a user