date range api
This commit is contained in:
@@ -68,6 +68,7 @@ LOCAL_APPS = [
|
||||
]
|
||||
|
||||
THIRD_PARTY_APPS = [
|
||||
"gisserver",
|
||||
"rest_framework",
|
||||
"widget_tweaks",
|
||||
"rest_framework_simplejwt",
|
||||
|
||||
@@ -1,24 +1,84 @@
|
||||
from django.contrib import admin
|
||||
from .models import EventCategory, Venue, EventMaster
|
||||
from .models import EventCategory, Venue, EventMaster, Event
|
||||
|
||||
|
||||
# Register your models here.
|
||||
class EventCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'description')
|
||||
search_fields = ('title', 'description')
|
||||
list_filter = ('title',)
|
||||
list_display = ("title", "description")
|
||||
search_fields = ("title", "description")
|
||||
list_filter = ("title",)
|
||||
|
||||
|
||||
class VenueAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'address', 'latitude', 'longitude')
|
||||
search_fields = ('title', 'address')
|
||||
list_filter = ('title',)
|
||||
list_display = ("id", "title", "address", "latitude", "longitude")
|
||||
search_fields = ("title", "address")
|
||||
list_filter = ("title",)
|
||||
|
||||
|
||||
class EventMasterAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'event_category', 'description')
|
||||
search_fields = ('title', 'description')
|
||||
list_filter = ('event_category', 'title')
|
||||
list_display = ("title", "event_category", "description")
|
||||
search_fields = ("title", "description")
|
||||
list_filter = ("event_category", "title")
|
||||
|
||||
|
||||
class EventAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"title",
|
||||
"category",
|
||||
"event_master",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"venue",
|
||||
"status",
|
||||
"draft",
|
||||
)
|
||||
list_filter = ("category", "status", "draft", "start_date", "end_date", "venue")
|
||||
search_fields = (
|
||||
"title",
|
||||
"description",
|
||||
"venue__title",
|
||||
"category__name",
|
||||
) # Assuming Venue and EventCategory have a title and name fields respectively
|
||||
date_hierarchy = "start_date" # Provides a quick date drill down functionality
|
||||
ordering = ("start_date", "from_time") # Orders events in the list view
|
||||
fieldsets = (
|
||||
(None, {"fields": ("title", "description", "image", "status")}),
|
||||
(
|
||||
"Date & Time",
|
||||
{
|
||||
"fields": ("start_date", "end_date", "from_time", "to_time"),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Venue Details",
|
||||
{
|
||||
"fields": ("venue", "venue_capacity"),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Category Details",
|
||||
{
|
||||
"fields": ("category", ),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Entry",
|
||||
{
|
||||
"fields": ("entry_type", "entry_fee", "key_guest", "age_group"),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Miscellaneous",
|
||||
{
|
||||
"fields": ("video_url", "draft"),
|
||||
},
|
||||
),
|
||||
)
|
||||
filter_horizontal = () # Use this if there are many-to-many fields
|
||||
raw_id_fields = ("venue", "category", "event_master")
|
||||
|
||||
|
||||
admin.site.register(Event, EventAdmin)
|
||||
admin.site.register(EventCategory, EventCategoryAdmin)
|
||||
admin.site.register(Venue, VenueAdmin)
|
||||
admin.site.register(EventMaster, EventMasterAdmin)
|
||||
|
||||
@@ -6,6 +6,7 @@ from manage_events.models import (
|
||||
Event,
|
||||
EventCategory,
|
||||
EventImage,
|
||||
Favorites,
|
||||
Venue,
|
||||
PrincipalPreference,
|
||||
)
|
||||
@@ -42,6 +43,7 @@ class EventDetailSerializer(serializers.ModelSerializer):
|
||||
images = serializers.SerializerMethodField()
|
||||
venue = VenueSerializer(read_only=True) # Use VenueSerializer for the venue field
|
||||
category = EventCategorySerializer(read_only=True)
|
||||
is_favorited = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Event
|
||||
@@ -63,6 +65,7 @@ class EventDetailSerializer(serializers.ModelSerializer):
|
||||
"key_guest",
|
||||
"age_group",
|
||||
"images",
|
||||
"is_favorited",
|
||||
]
|
||||
|
||||
def get_images(self, obj):
|
||||
@@ -71,6 +74,13 @@ class EventDetailSerializer(serializers.ModelSerializer):
|
||||
) # Ensure this uses the correct related_name from your model
|
||||
return EventImageSerializer(images, many=True, context=self.context).data
|
||||
|
||||
def get_is_favorited(self, obj):
|
||||
request = self.context.get("request")
|
||||
if request and hasattr(request, "user"):
|
||||
user = request.user
|
||||
return Favorites.objects.filter(event=obj, principal=user).exists()
|
||||
return False
|
||||
|
||||
|
||||
class CreateEventSerializer(serializers.ModelSerializer):
|
||||
images = serializers.ListField(
|
||||
@@ -174,3 +184,8 @@ class EventMasterSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = EventMaster
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class EventDateRangeSerializer(serializers.Serializer):
|
||||
start_date = serializers.DateField(format='%Y-%m-%d', input_formats=['%Y-%m-%d'])
|
||||
end_date = serializers.DateField(format='%Y-%m-%d', input_formats=['%Y-%m-%d'])
|
||||
@@ -25,6 +25,11 @@ urlpatterns = [
|
||||
views.VenueListView.as_view(),
|
||||
name="get_venue",
|
||||
),
|
||||
path(
|
||||
"venue/delete/<int:pk>/",
|
||||
views.VenueDeleteAPIView.as_view(),
|
||||
name="venue-delete",
|
||||
),
|
||||
path(
|
||||
"event-master/search/",
|
||||
views.EventMasterSearchAPIView.as_view(),
|
||||
@@ -74,4 +79,14 @@ urlpatterns = [
|
||||
views.EventFilterByLocationAPIView.as_view(),
|
||||
name="filter-events-by-location",
|
||||
),
|
||||
# Events filtered by Princiapl's Favorites
|
||||
path(
|
||||
"favorites/events/", views.FavoriteEventsList.as_view(), name="favorite-events"
|
||||
),
|
||||
# Events filtered by Date Range
|
||||
path(
|
||||
"events/date-range/",
|
||||
views.EventDateRangeAPIView.as_view(),
|
||||
name="event-date-range",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -14,6 +14,7 @@ from goodtimes.utils import ApiResponse, CapacityError
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from manage_events.api.serializers import (
|
||||
EventDateRangeSerializer,
|
||||
EventMasterSearchSerializer,
|
||||
EventMasterSerializer,
|
||||
CreateEventSerializer,
|
||||
@@ -36,7 +37,7 @@ from manage_events.models import (
|
||||
)
|
||||
import requests
|
||||
|
||||
from manage_events.utils import filter_events_by_location
|
||||
from manage_events.utils import filter_events_by_location, haversine_one
|
||||
|
||||
|
||||
class CreateEventApi(APIView):
|
||||
@@ -75,6 +76,30 @@ class CreateVenueApi(APIView):
|
||||
)
|
||||
|
||||
|
||||
class VenueDeleteAPIView(APIView):
|
||||
"""
|
||||
API view to set a venue's 'deleted' to True and 'active' to False.
|
||||
"""
|
||||
|
||||
def patch(self, request, pk):
|
||||
try:
|
||||
venue = Venue.objects.get(pk=pk)
|
||||
venue.deleted = True
|
||||
venue.active = False
|
||||
venue.save()
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_200_OK,
|
||||
message=constants.SUCCESS,
|
||||
data="Venue deleted successfully",
|
||||
)
|
||||
except Venue.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
message=constants.FAILURE,
|
||||
errors="Venue not found",
|
||||
)
|
||||
|
||||
|
||||
class EventsAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
@@ -449,16 +474,19 @@ class EventStatusUpdateAPIView(APIView):
|
||||
)
|
||||
|
||||
|
||||
# Filter Events within 10 KMs
|
||||
class EventFilterByLocationAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
principal = request.user
|
||||
|
||||
today = timezone.now().date()
|
||||
# Fetching user location from IAmPrincipalLocation
|
||||
try:
|
||||
user_location = IAmPrincipalLocation.objects.filter(principal=principal).last()
|
||||
user_location = IAmPrincipalLocation.objects.filter(
|
||||
principal=principal
|
||||
).last()
|
||||
user_lat = user_location.latitude
|
||||
user_lon = user_location.longitude
|
||||
except IAmPrincipalLocation.DoesNotExist:
|
||||
@@ -468,12 +496,31 @@ class EventFilterByLocationAPIView(APIView):
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
# Now filter events based on user location
|
||||
events = filter_events_by_location(user_lat, user_lon)
|
||||
print("events: ", events)
|
||||
# Assuming you only want current and future events
|
||||
today = timezone.now().date()
|
||||
events = events.filter(Q(end_date__gte=today) | Q(start_date__gte=today))
|
||||
max_distance_km = 10 # Set your desired maximum distance
|
||||
current_and_future_events_query = Q(active=True, deleted=False, draft=False) & (
|
||||
Q(start_date__lte=today, end_date__gte=today) | Q(start_date__gt=today)
|
||||
)
|
||||
|
||||
# Get the queryset based on the filter conditions
|
||||
events_queryset = Event.objects.filter(current_and_future_events_query)
|
||||
|
||||
venue_ids = events_queryset.values_list("venue", flat=True).distinct()
|
||||
venues = Venue.objects.filter(id__in=venue_ids)
|
||||
|
||||
venues_within_range = []
|
||||
for venue in venues:
|
||||
distance = haversine_one(
|
||||
user_lon, user_lat, venue.longitude, venue.latitude
|
||||
)
|
||||
print("distance: ", distance)
|
||||
if distance <= max_distance_km:
|
||||
print(
|
||||
venue
|
||||
) # This will print the venue object, or whatever __str__ returns for the venue model
|
||||
venues_within_range.append(venue.id)
|
||||
print("venues_within_range: ", venues_within_range)
|
||||
# venues_data = [venue_to_dict(venue) for venue in venues_within_range]
|
||||
events = Event.objects.filter(venue__id__in=venues_within_range)
|
||||
|
||||
# Serialize and return the filtered events
|
||||
serializer = EventDetailSerializer(
|
||||
@@ -484,3 +531,62 @@ class EventFilterByLocationAPIView(APIView):
|
||||
message=constants.SUCCESS,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
# Filter Principal's Favorites Events
|
||||
class FavoriteEventsList(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
principal = request.user
|
||||
events = Event.objects.filter(
|
||||
id__in=Favorites.objects.filter(principal=principal)
|
||||
.select_related("event")
|
||||
.values_list("event_id", flat=True),
|
||||
deleted=False,
|
||||
active=True,
|
||||
draft=False,
|
||||
)
|
||||
serializer = EventDetailSerializer(
|
||||
events, context={"request": request}, many=True
|
||||
)
|
||||
return ApiResponse.success(
|
||||
data=serializer.data,
|
||||
message=constants.SUCCESS,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class EventDateRangeAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
serializer = EventDateRangeSerializer(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
errors=serializer.errors,
|
||||
message=constants.FAILURE,
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
start_date = serializer.validated_data["start_date"]
|
||||
end_date = serializer.validated_data["end_date"]
|
||||
|
||||
events = Event.objects.filter(
|
||||
Q(end_date__gte=start_date)
|
||||
& Q(start_date__lte=end_date)
|
||||
& Q(deleted=False)
|
||||
& Q(active=True)
|
||||
& Q(draft=False)
|
||||
)
|
||||
|
||||
serializer = EventDetailSerializer(
|
||||
events, context={"request": request}, many=True
|
||||
)
|
||||
return ApiResponse.success(
|
||||
data=serializer.data,
|
||||
message=constants.SUCCESS,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from django.db import models
|
||||
from accounts.models import BaseModel, IAmPrincipal
|
||||
from django.db import transaction
|
||||
|
||||
# from django.contrib.gis.db import models as gis_models
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class EventCategory(BaseModel):
|
||||
title = models.CharField(max_length=255)
|
||||
@@ -50,7 +52,9 @@ class EventMaster(BaseModel):
|
||||
class Event(BaseModel):
|
||||
title = models.CharField(max_length=255)
|
||||
category = models.ForeignKey(EventCategory, on_delete=models.CASCADE)
|
||||
event_master = models.ForeignKey(EventMaster, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
event_master = models.ForeignKey(
|
||||
EventMaster, on_delete=models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
description = models.TextField(blank=True, null=True)
|
||||
image = models.ImageField(upload_to="event", null=True, blank=True)
|
||||
status = models.CharField(
|
||||
@@ -123,11 +127,13 @@ class PrincipalPreference(BaseModel):
|
||||
|
||||
|
||||
class Favorites(models.Model):
|
||||
principal = models.ForeignKey(IAmPrincipal, on_delete=models.CASCADE, related_name='favorited_by')
|
||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='favorites')
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal, on_delete=models.CASCADE, related_name="favorited_by"
|
||||
)
|
||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="favorites")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('principal', 'event')
|
||||
unique_together = ("principal", "event")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.principal}'s favorite: {self.event.title}"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import math
|
||||
from accounts.models import IAmPrincipalLocation
|
||||
from manage_events.models import Event, Venue
|
||||
|
||||
|
||||
@@ -36,3 +37,36 @@ def filter_events_by_location(user_lat, user_lon, radius_km=10):
|
||||
# Filter events based on the venues within the radius
|
||||
events = Event.objects.filter(venue__id__in=venues_within_radius)
|
||||
return events
|
||||
|
||||
|
||||
from math import sin, cos, radians, sqrt, atan2
|
||||
|
||||
|
||||
def haversine_one(lon1, lat1, lon2, lat2):
|
||||
"""
|
||||
Calculates the distance between two points on a sphere using the Haversine formula.
|
||||
|
||||
Args:
|
||||
lon1 (float): Longitude of the first point.
|
||||
lat1 (float): Latitude of the first point.
|
||||
lon2 (float): Longitude of the second point.
|
||||
lat2 (float): Latitude of the second point.
|
||||
|
||||
Returns:
|
||||
float: Distance in kilometers between the two points.
|
||||
"""
|
||||
R = 6371 # Earth's radius in kilometers
|
||||
|
||||
dlon = radians(lon2 - lon1)
|
||||
dlat = radians(lat2 - lat1)
|
||||
|
||||
a = sin(dlat / 2) * sin(dlat / 2) + cos(radians(lat1)) * cos(radians(lat2)) * sin(
|
||||
dlon / 2
|
||||
) * sin(dlon / 2)
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
|
||||
return R * c
|
||||
|
||||
|
||||
# Example usage:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user