diff --git a/api/serializers/event.py b/api/serializers/event.py index ada01b0..751cfeb 100644 --- a/api/serializers/event.py +++ b/api/serializers/event.py @@ -16,7 +16,16 @@ class EventSerializer(serializers.ModelSerializer): event_categories = EventCategory.objects.filter(event=instance).filter(active=True).all() event_tags = EventTag.objects.filter(event=instance).filter(active=True).all() + representation['location'] = { + 'lng': instance.coordinates.x if instance.coordinates else None, + 'lat': instance.coordinates.y if instance.coordinates else None + } + representation['categories'] = self._parse_categories(event_categories) + representation['tags'] = self._parse_tags(event_tags) + return representation + + def _parse_categories(self, event_categories): categories = [] if event_categories.exists(): for event_category in event_categories: @@ -26,7 +35,9 @@ class EventSerializer(serializers.ModelSerializer): 'description': event_category.category.description, '_meta': model_to_dict(event_category) }) + return categories + def _parse_tags(self, event_tags): tags = [] if event_tags.exists(): for event_tag in event_tags: @@ -35,7 +46,4 @@ class EventSerializer(serializers.ModelSerializer): 'name': event_tag.tag.name, '_meta': model_to_dict(event_tag) }) - - representation['categories'] = categories - representation['tags'] = tags - return representation + return tags diff --git a/api/views/base.py b/api/views/base.py index 909d64c..26e2b1d 100644 --- a/api/views/base.py +++ b/api/views/base.py @@ -21,3 +21,9 @@ class BaseView(APIView): response = Response() response.data = serialized_data return response + + def error_response(self, status_code, description): + response = Response() + response.status_code = status_code + response.data = {"error": description} + return response diff --git a/api/views/event.py b/api/views/event.py index 64ebb35..d9ad4e5 100644 --- a/api/views/event.py +++ b/api/views/event.py @@ -1,5 +1,7 @@ import json +from django.contrib.gis.geos import Point +from django.contrib.gis.measure import D from django.db import transaction from django.shortcuts import get_object_or_404 @@ -15,13 +17,35 @@ from web.models.event_tag import EventTag class EventView(BaseView): SERIALIZER = EventSerializer - def get(self, request, event_id): - event = get_object_or_404(Event, pk=event_id, active=True) - return self._build_response(event) + def get(self, request, event_id=None): + if event_id: + event = get_object_or_404(Event, pk=event_id, active=True) + return self._build_response(event) + else: + return self._get_events_by_radius(request) + + def _get_events_by_radius(self, request): + lat = request.GET.get('lat') + lng = request.GET.get('lng') + r = request.GET.get('r') + + if all([lat, lng, r]): + try: + user_location = Point(float(lng), float(lat), srid=4326) + events = Event.objects.filter(active=True).filter(coordinates__dwithin=(user_location, D(mi=float(r)))).all() + return self._build_multi_response(events) + except ValueError: + return self.error_response(400, 'Invalid coordinates or radius format') + else: + return self.error_response(400, 'Must include lat, lng, and r in query string') @transaction.atomic def post(self, request): data = json.loads(request.body) + + location = data.get('location', {}) + coordinates = Point(location.get("lng"), location.get("lat"), srid=4326) + event = Event( name=data.get('name'), description=data.get('description'), @@ -35,6 +59,7 @@ class EventView(BaseView): rain_date=data.get('rain_date'), email=data.get('email'), phone_number=data.get('phone_number'), + coordinates=coordinates, ) event.save() @@ -78,6 +103,11 @@ class EventView(BaseView): event = get_object_or_404(Event, pk=event_id) + location = data.get('location', {}) + if location: + coordinates = Point(location.get("lng"), location.get("lat"), srid=4326) + event.coordinates = coordinates + event.name = data.get('name', event.name) event.description = data.get('description', event.description) event.url = data.get('url', event.url) diff --git a/web/migrations/0004_alter_event_coordinates.py b/web/migrations/0004_alter_event_coordinates.py new file mode 100644 index 0000000..5934d58 --- /dev/null +++ b/web/migrations/0004_alter_event_coordinates.py @@ -0,0 +1,21 @@ +# Generated by Django 6.0.6 on 2026-06-21 19:33 + +import django.contrib.gis.db.models.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("web", "0003_event_coordinates"), + ] + + operations = [ + migrations.AlterField( + model_name="event", + name="coordinates", + field=django.contrib.gis.db.models.fields.PointField( + blank=True, default=None, geography=True, null=True, srid=4326 + ), + ), + ] diff --git a/web/models/event.py b/web/models/event.py index 7b4d246..4ca00ea 100644 --- a/web/models/event.py +++ b/web/models/event.py @@ -14,7 +14,7 @@ class Event(BaseModel): description = models.TextField() url = models.URLField() address = models.CharField() - coordinates = models.PointField(blank=True, default=None, null=True) + coordinates = models.PointField(blank=True, default=None, null=True, srid=4326, geography=True) status = models.CharField(max_length=20, choices=Status.choices, default=Status.SCHEDULED) price = models.DecimalField(max_digits=10, default=None, blank=True, decimal_places=2) require_rsvp = models.BooleanField()