date range api

This commit is contained in:
rizwanisready
2024-03-07 22:30:16 +05:30
parent 8d199f5db9
commit 2d93fe048a
7 changed files with 260 additions and 23 deletions

View File

@@ -68,6 +68,7 @@ LOCAL_APPS = [
]
THIRD_PARTY_APPS = [
"gisserver",
"rest_framework",
"widget_tweaks",
"rest_framework_simplejwt",

View File

@@ -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)

View File

@@ -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'])

View File

@@ -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",
),
]

View File

@@ -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,
)

View File

@@ -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}"

View File

@@ -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: