mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 17:51:08 -05:00
201 lines
7.3 KiB
Python
201 lines
7.3 KiB
Python
import json
|
|
import requests
|
|
from django.views.generic import View
|
|
from django.http import JsonResponse
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.core.cache import cache
|
|
from django.conf import settings
|
|
from django.views.decorators.http import require_http_methods
|
|
from django.utils.decorators import method_decorator
|
|
from django.views.decorators.csrf import csrf_protect
|
|
from django.db.models import Q
|
|
from .models import Location
|
|
|
|
class LocationSearchView(View):
|
|
"""
|
|
View for searching locations using OpenStreetMap Nominatim.
|
|
Returns search results in JSON format.
|
|
"""
|
|
|
|
@method_decorator(csrf_protect)
|
|
def get(self, request, *args, **kwargs):
|
|
query = request.GET.get('q', '').strip()
|
|
filter_type = request.GET.get('type', '') # country, state, city
|
|
filter_parks = request.GET.get('filter_parks', 'false') == 'true'
|
|
|
|
if not query:
|
|
return JsonResponse({'results': []})
|
|
|
|
# Check cache first
|
|
cache_key = f'location_search_{query}_{filter_type}_{filter_parks}'
|
|
cached_results = cache.get(cache_key)
|
|
if cached_results:
|
|
return JsonResponse({'results': cached_results})
|
|
|
|
# Search OpenStreetMap
|
|
try:
|
|
params = {
|
|
'q': query,
|
|
'format': 'json',
|
|
'addressdetails': 1,
|
|
'limit': 10
|
|
}
|
|
|
|
# Add type-specific filters
|
|
if filter_type == 'country':
|
|
params['featuretype'] = 'country'
|
|
elif filter_type == 'state':
|
|
params['featuretype'] = 'state'
|
|
elif filter_type == 'city':
|
|
params['featuretype'] = 'city'
|
|
|
|
response = requests.get(
|
|
'https://nominatim.openstreetmap.org/search',
|
|
params=params,
|
|
headers={'User-Agent': 'ThrillWiki/1.0'}
|
|
)
|
|
response.raise_for_status()
|
|
results = response.json()
|
|
except requests.RequestException as e:
|
|
return JsonResponse({
|
|
'error': 'Failed to fetch location data',
|
|
'details': str(e)
|
|
}, status=500)
|
|
|
|
# Process and format results
|
|
formatted_results = []
|
|
for result in results:
|
|
address = result.get('address', {})
|
|
formatted_result = {
|
|
'name': result.get('display_name', ''),
|
|
'lat': result.get('lat'),
|
|
'lon': result.get('lon'),
|
|
'type': result.get('type', ''),
|
|
'address': {
|
|
'street': address.get('road', ''),
|
|
'house_number': address.get('house_number', ''),
|
|
'city': address.get('city', '') or address.get('town', '') or address.get('village', ''),
|
|
'state': address.get('state', ''),
|
|
'country': address.get('country', ''),
|
|
'postcode': address.get('postcode', '')
|
|
}
|
|
}
|
|
|
|
# If filtering by parks, only include results that have parks
|
|
if filter_parks:
|
|
location_exists = Location.objects.filter(
|
|
Q(country__icontains=formatted_result['address']['country']) &
|
|
(Q(state__icontains=formatted_result['address']['state']) if formatted_result['address']['state'] else Q()) &
|
|
(Q(city__icontains=formatted_result['address']['city']) if formatted_result['address']['city'] else Q())
|
|
).exists()
|
|
if not location_exists:
|
|
continue
|
|
|
|
formatted_results.append(formatted_result)
|
|
|
|
# Cache results for 1 hour
|
|
cache.set(cache_key, formatted_results, 3600)
|
|
|
|
return JsonResponse({'results': formatted_results})
|
|
|
|
class LocationCreateView(LoginRequiredMixin, View):
|
|
"""View for creating new Location objects"""
|
|
|
|
@method_decorator(csrf_protect)
|
|
def post(self, request, *args, **kwargs):
|
|
form = LocationForm(request.POST)
|
|
if form.is_valid():
|
|
location = form.save()
|
|
return JsonResponse({
|
|
'id': location.id,
|
|
'name': location.name,
|
|
'formatted_address': location.get_formatted_address(),
|
|
'coordinates': location.coordinates
|
|
})
|
|
return JsonResponse({'errors': form.errors}, status=400)
|
|
|
|
class LocationUpdateView(LoginRequiredMixin, View):
|
|
"""View for updating existing Location objects"""
|
|
|
|
@method_decorator(csrf_protect)
|
|
def post(self, request, *args, **kwargs):
|
|
location = Location.objects.get(pk=kwargs['pk'])
|
|
form = LocationForm(request.POST, instance=location)
|
|
if form.is_valid():
|
|
location = form.save()
|
|
return JsonResponse({
|
|
'id': location.id,
|
|
'name': location.name,
|
|
'formatted_address': location.get_formatted_address(),
|
|
'coordinates': location.coordinates
|
|
})
|
|
return JsonResponse({'errors': form.errors}, status=400)
|
|
|
|
class LocationDeleteView(LoginRequiredMixin, View):
|
|
"""View for deleting Location objects"""
|
|
|
|
@method_decorator(csrf_protect)
|
|
def post(self, request, *args, **kwargs):
|
|
try:
|
|
location = Location.objects.get(pk=kwargs['pk'])
|
|
location.delete()
|
|
return JsonResponse({'status': 'success'})
|
|
except Location.DoesNotExist:
|
|
return JsonResponse({'error': 'Location not found'}, status=404)
|
|
|
|
@require_http_methods(["GET"])
|
|
def reverse_geocode(request):
|
|
"""
|
|
View for reverse geocoding coordinates to address using OpenStreetMap.
|
|
Returns address details in JSON format.
|
|
"""
|
|
lat = request.GET.get('lat')
|
|
lon = request.GET.get('lon')
|
|
|
|
if not lat or not lon:
|
|
return JsonResponse({'error': 'Latitude and longitude are required'}, status=400)
|
|
|
|
# Check cache first
|
|
cache_key = f'reverse_geocode_{lat}_{lon}'
|
|
cached_result = cache.get(cache_key)
|
|
if cached_result:
|
|
return JsonResponse(cached_result)
|
|
|
|
try:
|
|
response = requests.get(
|
|
'https://nominatim.openstreetmap.org/reverse',
|
|
params={
|
|
'lat': lat,
|
|
'lon': lon,
|
|
'format': 'json',
|
|
'addressdetails': 1
|
|
},
|
|
headers={'User-Agent': 'ThrillWiki/1.0'}
|
|
)
|
|
response.raise_for_status()
|
|
result = response.json()
|
|
|
|
address = result.get('address', {})
|
|
formatted_result = {
|
|
'name': result.get('display_name', ''),
|
|
'address': {
|
|
'street': address.get('road', ''),
|
|
'house_number': address.get('house_number', ''),
|
|
'city': address.get('city', '') or address.get('town', '') or address.get('village', ''),
|
|
'state': address.get('state', ''),
|
|
'country': address.get('country', ''),
|
|
'postcode': address.get('postcode', '')
|
|
}
|
|
}
|
|
|
|
# Cache result for 1 day
|
|
cache.set(cache_key, formatted_result, 86400)
|
|
|
|
return JsonResponse(formatted_result)
|
|
|
|
except requests.RequestException as e:
|
|
return JsonResponse({
|
|
'error': 'Failed to fetch address data',
|
|
'details': str(e)
|
|
}, status=500)
|