feat: add source field with 3 options, fix EventListAPI fallback, add is_eventify_event to API response
- Event.source field updated: eventify, community, partner (radio select in form) - EventListAPI: fallback to all events when pincode returns < 6 - EventListAPI: include is_eventify_event and source in serializer - Admin API: add source to list serializer - Django admin: source in list_display, list_filter, list_editable - Event form template: proper radio button rendering for source field Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,36 @@ class EventTypeListAPIView(APIView):
|
||||
class EventListAPI(APIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
@staticmethod
|
||||
def _serialize_event(e, thumb_map):
|
||||
"""Slim serialization for list views — only fields the Flutter app uses."""
|
||||
img = thumb_map.get(e.id)
|
||||
lat = e.latitude
|
||||
lng = e.longitude
|
||||
desc = e.description or ''
|
||||
return {
|
||||
'id': e.id,
|
||||
'name': e.name or '',
|
||||
'title': e.title or '',
|
||||
'description': desc[:200] if len(desc) > 200 else desc,
|
||||
'start_date': str(e.start_date) if e.start_date else '',
|
||||
'end_date': str(e.end_date) if e.end_date else '',
|
||||
'start_time': str(e.start_time) if e.start_time else '',
|
||||
'end_time': str(e.end_time) if e.end_time else '',
|
||||
'pincode': e.pincode or '',
|
||||
'place': e.place or '',
|
||||
'is_bookable': bool(e.is_bookable),
|
||||
'event_type': e.event_type_id,
|
||||
'event_status': e.event_status or '',
|
||||
'venue_name': getattr(e, 'venue_name', '') or '',
|
||||
'latitude': float(lat) if lat is not None else None,
|
||||
'longitude': float(lng) if lng is not None else None,
|
||||
'location_name': getattr(e, 'location_name', '') or '',
|
||||
'thumb_img': img.event_image.url if img and img.event_image else '',
|
||||
'is_eventify_event': bool(e.is_eventify_event),
|
||||
'source': e.source or 'eventify',
|
||||
}
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
try:
|
||||
@@ -44,40 +74,53 @@ class EventListAPI(APIView):
|
||||
except Exception:
|
||||
data = {}
|
||||
|
||||
paginate = "page" in data
|
||||
page = int(data.get("page", 1))
|
||||
page_size = int(data.get("page_size", 15))
|
||||
pincode = data.get("pincode", "all")
|
||||
page = int(data.get("page", 1))
|
||||
page_size = int(data.get("page_size", 50))
|
||||
per_type = int(data.get("per_type", 0))
|
||||
|
||||
events = Event.objects.select_related('event_type').order_by('-created_date')
|
||||
# Build base queryset (lazy - no DB hit yet)
|
||||
MIN_EVENTS_THRESHOLD = 6
|
||||
qs = Event.objects.all()
|
||||
if pincode and pincode != 'all':
|
||||
pincode_qs = qs.filter(pincode=pincode)
|
||||
# Fallback to all events if pincode has too few
|
||||
if pincode_qs.count() >= MIN_EVENTS_THRESHOLD:
|
||||
qs = pincode_qs
|
||||
# else: keep qs as Event.objects.all()
|
||||
|
||||
total = events.count()
|
||||
|
||||
if paginate:
|
||||
start = (page - 1) * page_size
|
||||
end = start + page_size
|
||||
page_qs = list(events[start:end])
|
||||
if per_type > 0 and page == 1:
|
||||
# Diverse mode: one bounded query per event type
|
||||
type_ids = list(qs.values_list('event_type_id', flat=True).distinct())
|
||||
events_page = []
|
||||
for tid in sorted(type_ids):
|
||||
chunk = list(qs.filter(event_type_id=tid).order_by('-created_date')[:per_type])
|
||||
events_page.extend(chunk)
|
||||
total_count = qs.count()
|
||||
end = len(events_page)
|
||||
else:
|
||||
page_qs = list(events)
|
||||
start, end = 0, total
|
||||
# Standard pagination at DB level
|
||||
total_count = qs.count()
|
||||
qs = qs.order_by('-created_date')
|
||||
start = (page - 1) * page_size
|
||||
end = start + page_size
|
||||
events_page = list(qs[start:end])
|
||||
|
||||
event_ids = [e.id for e in page_qs]
|
||||
primary_images = EventImages.objects.filter(event_id__in=event_ids, is_primary=True)
|
||||
# Fetch images ONLY for the events we will return
|
||||
page_ids = [e.id for e in events_page]
|
||||
primary_images = EventImages.objects.filter(event_id__in=page_ids, is_primary=True)
|
||||
thumb_map = {img.event_id: img for img in primary_images}
|
||||
|
||||
event_list = []
|
||||
for e in page_qs:
|
||||
d = model_to_dict(e)
|
||||
img = thumb_map.get(e.id)
|
||||
d['thumb_img'] = img.event_image.url if img else ''
|
||||
event_list.append(d)
|
||||
# Serialize with direct attribute access (fast)
|
||||
event_list = [self._serialize_event(e, thumb_map) for e in events_page]
|
||||
|
||||
return JsonResponse({
|
||||
"status": "success",
|
||||
"events": event_list,
|
||||
"total": total,
|
||||
"total_count": total_count,
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"has_next": end < total,
|
||||
"has_next": end < total_count,
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)})
|
||||
@@ -110,6 +153,8 @@ class EventDetailAPI(APIView):
|
||||
|
||||
|
||||
class EventImagesListAPI(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request)
|
||||
@@ -139,6 +184,8 @@ class EventImagesListAPI(APIView):
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class EventsByCategoryAPI(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request)
|
||||
@@ -176,6 +223,8 @@ class EventsByCategoryAPI(APIView):
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class EventsByMonthYearAPI(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
"""
|
||||
API to get events by month and year.
|
||||
Returns dates that have events, total count, and date-wise breakdown.
|
||||
@@ -298,6 +347,8 @@ class EventsByMonthYearAPI(APIView):
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class EventsByDateAPI(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
"""
|
||||
API to get events occurring on a specific date.
|
||||
Returns complete event information with primary images.
|
||||
@@ -354,6 +405,8 @@ class EventsByDateAPI(APIView):
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class FeaturedEventsAPI(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
"""Returns events where is_featured=True — used for the homepage hero carousel."""
|
||||
|
||||
def post(self, request):
|
||||
@@ -380,6 +433,8 @@ class FeaturedEventsAPI(APIView):
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class TopEventsAPI(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
"""Returns events where is_top_event=True — used for the Top Events section."""
|
||||
|
||||
def post(self, request):
|
||||
|
||||
Reference in New Issue
Block a user