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

GEO Point checker!

This commit is contained in:
Sean Morley 2024-08-23 13:56:27 -04:00
parent 283431085f
commit 45196f9823
11 changed files with 129 additions and 6 deletions

View file

@ -58,6 +58,7 @@ INSTALLED_APPS = (
'adventures', 'adventures',
'worldtravel', 'worldtravel',
'users', 'users',
'django.contrib.gis',
) )
@ -100,7 +101,7 @@ SIMPLE_JWT = {
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql', 'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': getenv('PGDATABASE'), 'NAME': getenv('PGDATABASE'),
'USER': getenv('PGUSER'), 'USER': getenv('PGUSER'),
'PASSWORD': getenv('PGPASSWORD'), 'PASSWORD': getenv('PGPASSWORD'),

View file

@ -10,4 +10,5 @@ python-dotenv
psycopg2-binary psycopg2-binary
Pillow Pillow
whitenoise whitenoise
django-resized django-resized
django-geojson

View file

@ -4,7 +4,7 @@
{ {
"type": "Feature", "type": "Feature",
"geometry": { "geometry": {
"type": "Polygon", "type": "MultiPolygon",
"coordinates": [ "coordinates": [
[ [
[1.9221462784913, 48.457599361977], [1.9221462784913, 48.457599361977],

View file

@ -10,7 +10,7 @@
"ISOCODE": "MX-CMX" "ISOCODE": "MX-CMX"
}, },
"geometry": { "geometry": {
"type": "Polygon", "type": "MultiPolygon",
"coordinates": [ "coordinates": [
[ [
[-99.111241, 19.561498], [-99.111241, 19.561498],

View file

@ -16,7 +16,7 @@
"AWATER": 23736382213 "AWATER": 23736382213
}, },
"geometry": { "geometry": {
"type": "Polygon", "type": "MultiPolygon",
"coordinates": [ "coordinates": [
[ [
[-94.0430515276176, 32.6930299766656], [-94.0430515276176, 32.6930299766656],

View file

@ -4,11 +4,66 @@ from django.contrib.auth import get_user_model
import requests import requests
from worldtravel.models import Country, Region from worldtravel.models import Country, Region
from django.db import transaction from django.db import transaction
from django.contrib.gis.geos import GEOSGeometry, Polygon, MultiPolygon
from django.contrib.gis.geos.error import GEOSException
import json
from django.conf import settings from django.conf import settings
media_root = settings.MEDIA_ROOT media_root = settings.MEDIA_ROOT
def setGeometry(region_code):
# Assuming the file name is the country code (e.g., 'AU.json' for Australia)
country_code = region_code.split('-')[0]
json_file = os.path.join('static/data', f'{country_code.lower()}.json')
if not os.path.exists(json_file):
print(f'File {country_code}.json does not exist')
return None
try:
with open(json_file, 'r') as f:
geojson_data = json.load(f)
except json.JSONDecodeError as e:
print(f"Invalid JSON in file for {country_code}: {e}")
return None
if 'type' not in geojson_data or geojson_data['type'] != 'FeatureCollection':
print(f"Invalid GeoJSON structure for {country_code}: missing or incorrect 'type'")
return None
if 'features' not in geojson_data or not geojson_data['features']:
print(f"Invalid GeoJSON structure for {country_code}: missing or empty 'features'")
return None
for feature in geojson_data['features']:
try:
properties = feature.get('properties', {})
isocode = properties.get('ISOCODE')
if isocode == region_code:
geometry = feature['geometry']
geos_geom = GEOSGeometry(json.dumps(geometry))
if isinstance(geos_geom, Polygon):
Region.objects.filter(id=region_code).update(geometry=MultiPolygon([geos_geom]))
print(f"Updated geometry for region {region_code}")
return MultiPolygon([geos_geom])
elif isinstance(geos_geom, MultiPolygon):
Region.objects.filter(id=region_code).update(geometry=geos_geom)
print(f"Updated geometry for region {region_code}")
return geos_geom
else:
print(f"Unexpected geometry type for region {region_code}: {type(geos_geom)}")
return None
except (KeyError, ValueError, GEOSException) as e:
print(f"Error processing region {region_code}: {e}")
print(f"No matching region found for {region_code}")
return None
def saveCountryFlag(country_code): def saveCountryFlag(country_code):
flags_dir = os.path.join(media_root, 'flags') flags_dir = os.path.join(media_root, 'flags')
@ -616,7 +671,9 @@ class Command(BaseCommand):
) )
if created: if created:
self.stdout.write(f'Inserted {name} into worldtravel regions') self.stdout.write(f'Inserted {name} into worldtravel regions')
setGeometry(id)
else: else:
setGeometry(id)
self.stdout.write(f'Updated {name} in worldtravel regions') self.stdout.write(f'Updated {name} in worldtravel regions')
def insert_countries(self, countries): def insert_countries(self, countries):
@ -627,6 +684,7 @@ class Command(BaseCommand):
) )
if created: if created:
saveCountryFlag(country_code) saveCountryFlag(country_code)
self.stdout.write(f'Inserted {name} into worldtravel countries') self.stdout.write(f'Inserted {name} into worldtravel countries')
else: else:
saveCountryFlag(country_code) saveCountryFlag(country_code)
@ -641,5 +699,7 @@ class Command(BaseCommand):
) )
if created: if created:
self.stdout.write(f'Inserted {name} into worldtravel regions') self.stdout.write(f'Inserted {name} into worldtravel regions')
setGeometry(id)
else: else:
setGeometry(id)
self.stdout.write(f'{name} already exists in worldtravel regions') self.stdout.write(f'{name} already exists in worldtravel regions')

View file

@ -0,0 +1,19 @@
# Generated by Django 5.0.8 on 2024-08-23 17:01
import django.contrib.gis.db.models.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('worldtravel', '0003_alter_region_name_en'),
]
operations = [
migrations.AddField(
model_name='country',
name='geometry',
field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 5.0.8 on 2024-08-23 17:47
import django.contrib.gis.db.models.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('worldtravel', '0004_country_geometry'),
]
operations = [
migrations.RemoveField(
model_name='country',
name='geometry',
),
migrations.AddField(
model_name='region',
name='geometry',
field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326),
),
]

View file

@ -1,6 +1,7 @@
from django.db import models from django.db import models
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.contrib.gis.db import models as gis_models
User = get_user_model() User = get_user_model()
@ -34,6 +35,7 @@ class Country(models.Model):
choices=CONTINENT_CHOICES, choices=CONTINENT_CHOICES,
default=AFRICA default=AFRICA
) )
class Meta: class Meta:
verbose_name = "Country" verbose_name = "Country"
@ -47,6 +49,7 @@ class Region(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
name_en = models.CharField(max_length=100, blank=True, null=True) name_en = models.CharField(max_length=100, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE) country = models.ForeignKey(Country, on_delete=models.CASCADE)
geometry = gis_models.MultiPolygonField(srid=4326, null=True, blank=True)
def __str__(self): def __str__(self):
return self.name return self.name

View file

@ -16,7 +16,7 @@ class CountrySerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Country model = Country
fields = '__all__' # Serialize all fields of the Adventure model fields = '__all__' # Serialize all fields of the Adventure model
read_only_fields = ['id', 'name', 'country_code', 'continent', 'flag_url'] read_only_fields = ['id', 'name', 'country_code', 'continent', 'flag_url', 'geometry']
class RegionSerializer(serializers.ModelSerializer): class RegionSerializer(serializers.ModelSerializer):
class Meta: class Meta:

View file

@ -8,7 +8,10 @@ from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes from rest_framework.decorators import api_view, permission_classes
import os import os
import json import json
from django.http import JsonResponse
from django.contrib.gis.geos import Point
from django.conf import settings from django.conf import settings
from rest_framework.decorators import action
from django.contrib.staticfiles import finders from django.contrib.staticfiles import finders
@api_view(['GET']) @api_view(['GET'])
@ -34,6 +37,19 @@ class CountryViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CountrySerializer serializer_class = CountrySerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@action(detail=False, methods=['get'])
def check_point_in_region(self, request):
lat = float(request.query_params.get('lat'))
lon = float(request.query_params.get('lon'))
point = Point(lon, lat, srid=4326)
region = Region.objects.filter(geometry__contains=point).first()
if region:
return Response({'in_region': True, 'region_name': region.name})
else:
return Response({'in_region': False})
class RegionViewSet(viewsets.ReadOnlyModelViewSet): class RegionViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Region.objects.all() queryset = Region.objects.all()
serializer_class = RegionSerializer serializer_class = RegionSerializer