mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 18:51:07 -05:00
feat: Implement ride management views and utility functions
- Added functions for checking user privileges, handling photo uploads, preparing form data, and managing form errors. - Created views for listing, creating, updating, and displaying rides, including category-specific views. - Integrated submission handling for ride changes and improved user feedback through messages. - Enhanced data handling with appropriate context and queryset management for better performance and usability.
This commit is contained in:
590
rides/views.py
590
rides/views.py
@@ -1,3 +1,4 @@
|
||||
from typing import Any, Dict, Optional, Tuple, Union, cast
|
||||
from django.views.generic import DetailView, ListView, CreateView, UpdateView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
@@ -6,344 +7,464 @@ from django.db.models import Q
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib import messages
|
||||
from django.http import JsonResponse, HttpResponseRedirect, Http404
|
||||
from django.http import (
|
||||
JsonResponse,
|
||||
HttpResponseRedirect,
|
||||
Http404,
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
)
|
||||
from django.db.models import Count
|
||||
from django.core.files.uploadedfile import UploadedFile
|
||||
from django.forms import ModelForm
|
||||
from .models import Ride, RollerCoasterStats
|
||||
from .forms import RideForm
|
||||
from parks.models import Park
|
||||
from core.views import SlugRedirectMixin
|
||||
from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin
|
||||
from moderation.models import EditSubmission
|
||||
from media.models import Photo
|
||||
from accounts.models import User
|
||||
|
||||
|
||||
def is_privileged_user(user: Any) -> bool:
|
||||
"""Check if the user has privileged access.
|
||||
|
||||
Args:
|
||||
user: The user to check
|
||||
|
||||
Returns:
|
||||
bool: True if user has privileged or higher privileges
|
||||
"""
|
||||
return isinstance(user, User) and user.role in ["MODERATOR", "ADMIN", "SUPERUSER"]
|
||||
|
||||
|
||||
def handle_photo_uploads(request: HttpRequest, ride: Ride) -> int:
|
||||
"""Handle photo uploads for a ride.
|
||||
|
||||
Args:
|
||||
request: The HTTP request containing files
|
||||
ride: The ride to attach photos to
|
||||
|
||||
Returns:
|
||||
int: Number of successfully uploaded photos
|
||||
"""
|
||||
uploaded_count = 0
|
||||
photos = request.FILES.getlist("photos")
|
||||
for photo_file in photos:
|
||||
try:
|
||||
Photo.objects.create(
|
||||
image=photo_file,
|
||||
uploaded_by=request.user,
|
||||
content_type=ContentType.objects.get_for_model(Ride),
|
||||
object_id=ride.pk,
|
||||
)
|
||||
uploaded_count += 1
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error uploading photo {photo_file.name}: {str(e)}")
|
||||
return uploaded_count
|
||||
|
||||
|
||||
def prepare_form_data(cleaned_data: Dict[str, Any], park: Park) -> Dict[str, Any]:
|
||||
"""Prepare form data for submission.
|
||||
|
||||
Args:
|
||||
cleaned_data: The form's cleaned data
|
||||
park: The park instance
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Processed form data ready for submission
|
||||
"""
|
||||
data = cleaned_data.copy()
|
||||
data["park"] = park.pk
|
||||
if data.get("park_area"):
|
||||
data["park_area"] = data["park_area"].pk
|
||||
if data.get("manufacturer"):
|
||||
data["manufacturer"] = data["manufacturer"].pk
|
||||
return data
|
||||
|
||||
|
||||
def handle_form_errors(request: HttpRequest, form: ModelForm) -> None:
|
||||
"""Handle form validation errors by adding appropriate error messages.
|
||||
|
||||
Args:
|
||||
request: The HTTP request
|
||||
form: The form containing validation errors
|
||||
"""
|
||||
messages.error(
|
||||
request,
|
||||
"Please correct the errors below. Required fields are marked with an asterisk (*).",
|
||||
)
|
||||
for field, errors in form.errors.items():
|
||||
for error in errors:
|
||||
messages.error(request, f"{field}: {error}")
|
||||
|
||||
|
||||
def create_edit_submission(
|
||||
request: HttpRequest,
|
||||
submission_type: str,
|
||||
changes: Dict[str, Any],
|
||||
object_id: Optional[int] = None,
|
||||
) -> EditSubmission:
|
||||
"""Create an EditSubmission object for ride changes.
|
||||
|
||||
Args:
|
||||
request: The HTTP request
|
||||
submission_type: Type of submission (CREATE or EDIT)
|
||||
changes: The changes to be submitted
|
||||
object_id: Optional ID of the existing object for edits
|
||||
|
||||
Returns:
|
||||
EditSubmission: The created submission object
|
||||
"""
|
||||
submission_data = {
|
||||
"user": request.user,
|
||||
"content_type": ContentType.objects.get_for_model(Ride),
|
||||
"submission_type": submission_type,
|
||||
"changes": changes,
|
||||
"reason": request.POST.get("reason", ""),
|
||||
"source": request.POST.get("source", ""),
|
||||
}
|
||||
|
||||
if object_id is not None:
|
||||
submission_data["object_id"] = object_id
|
||||
|
||||
return EditSubmission.objects.create(**submission_data)
|
||||
|
||||
|
||||
def handle_privileged_save(
|
||||
request: HttpRequest, form: RideForm, submission: EditSubmission
|
||||
) -> Tuple[bool, str]:
|
||||
"""Handle saving form and updating submission for privileged users.
|
||||
|
||||
Args:
|
||||
request: The HTTP request
|
||||
form: The form to save
|
||||
submission: The edit submission to update
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str]: Success status and error message (empty string if successful)
|
||||
"""
|
||||
try:
|
||||
ride = form.save()
|
||||
if submission.submission_type == "CREATE":
|
||||
submission.object_id = ride.pk
|
||||
submission.status = "APPROVED"
|
||||
submission.handled_by = request.user
|
||||
submission.save()
|
||||
return True, ""
|
||||
except Exception as e:
|
||||
error_msg = (
|
||||
f"Error {submission.submission_type.lower()}ing ride: {str(e)}. "
|
||||
"Please check your input and try again."
|
||||
)
|
||||
return False, error_msg
|
||||
|
||||
|
||||
class SingleCategoryListView(ListView):
|
||||
model = Ride
|
||||
template_name = 'rides/ride_category_list.html'
|
||||
context_object_name = 'categories'
|
||||
template_name = "rides/ride_category_list.html"
|
||||
context_object_name = "categories"
|
||||
|
||||
def get_category_code(self):
|
||||
category = self.kwargs.get('category')
|
||||
if not category:
|
||||
raise Http404("Category not found")
|
||||
return category
|
||||
def get_category_code(self) -> str:
|
||||
if category := self.kwargs.get("category"):
|
||||
return category
|
||||
raise Http404("Category not found")
|
||||
|
||||
def get_queryset(self):
|
||||
category_code = self.get_category_code()
|
||||
category_name = dict(Ride.CATEGORY_CHOICES)[category_code]
|
||||
|
||||
rides = Ride.objects.filter(category=category_code).select_related(
|
||||
'park', 'manufacturer'
|
||||
).order_by('name')
|
||||
|
||||
|
||||
rides = (
|
||||
Ride.objects.filter(category=category_code)
|
||||
.select_related("park", "manufacturer")
|
||||
.order_by("name")
|
||||
)
|
||||
|
||||
return {category_name: rides} if rides.exists() else {}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
category_code = self.get_category_code()
|
||||
category_name = dict(Ride.CATEGORY_CHOICES)[category_code]
|
||||
context['title'] = f'All {category_name}s'
|
||||
context['category_code'] = category_code
|
||||
context["title"] = f"All {category_name}s"
|
||||
context["category_code"] = category_code
|
||||
return context
|
||||
|
||||
|
||||
class ParkSingleCategoryListView(ListView):
|
||||
model = Ride
|
||||
template_name = 'rides/ride_category_list.html'
|
||||
context_object_name = 'categories'
|
||||
template_name = "rides/ride_category_list.html"
|
||||
context_object_name = "categories"
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
def setup(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
|
||||
super().setup(request, *args, **kwargs)
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs['park_slug'])
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs["park_slug"])
|
||||
|
||||
def get_category_code(self):
|
||||
category = self.kwargs.get('category')
|
||||
if not category:
|
||||
raise Http404("Category not found")
|
||||
return category
|
||||
def get_category_code(self) -> str:
|
||||
if category := self.kwargs.get("category"):
|
||||
return category
|
||||
raise Http404("Category not found")
|
||||
|
||||
def get_queryset(self):
|
||||
category_code = self.get_category_code()
|
||||
category_name = dict(Ride.CATEGORY_CHOICES)[category_code]
|
||||
|
||||
rides = Ride.objects.filter(
|
||||
park=self.park,
|
||||
category=category_code
|
||||
).select_related('manufacturer').order_by('name')
|
||||
|
||||
|
||||
rides = (
|
||||
Ride.objects.filter(park=self.park, category=category_code)
|
||||
.select_related("manufacturer")
|
||||
.order_by("name")
|
||||
)
|
||||
|
||||
return {category_name: rides} if rides.exists() else {}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['park'] = self.park
|
||||
context["park"] = self.park
|
||||
category_code = self.get_category_code()
|
||||
category_name = dict(Ride.CATEGORY_CHOICES)[category_code]
|
||||
context['title'] = f'{category_name}s at {self.park.name}'
|
||||
context['category_code'] = category_code
|
||||
context["title"] = f"{category_name}s at {self.park.name}"
|
||||
context["category_code"] = category_code
|
||||
return context
|
||||
|
||||
|
||||
class RideCreateView(LoginRequiredMixin, CreateView):
|
||||
model = Ride
|
||||
form_class = RideForm
|
||||
template_name = 'rides/ride_form.html'
|
||||
template_name = "rides/ride_form.html"
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
def setup(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
|
||||
super().setup(request, *args, **kwargs)
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs['park_slug'])
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs["park_slug"])
|
||||
|
||||
def get_form_kwargs(self):
|
||||
def get_form_kwargs(self) -> Dict[str, Any]:
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['park'] = self.park
|
||||
kwargs["park"] = self.park
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.park = self.park
|
||||
|
||||
cleaned_data = form.cleaned_data.copy()
|
||||
cleaned_data['park'] = self.park.id
|
||||
# Convert model instances to IDs for JSON serialization
|
||||
if cleaned_data.get('park_area'):
|
||||
cleaned_data['park_area'] = cleaned_data['park_area'].id
|
||||
if cleaned_data.get('manufacturer'):
|
||||
cleaned_data['manufacturer'] = cleaned_data['manufacturer'].id
|
||||
def handle_submission(
|
||||
self, form: RideForm, cleaned_data: Dict[str, Any]
|
||||
) -> HttpResponseRedirect:
|
||||
"""Handle the form submission.
|
||||
|
||||
# Create submission record
|
||||
submission = EditSubmission.objects.create(
|
||||
user=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Ride),
|
||||
submission_type='CREATE',
|
||||
changes=cleaned_data,
|
||||
reason=self.request.POST.get('reason', ''),
|
||||
source=self.request.POST.get('source', '')
|
||||
)
|
||||
|
||||
# If user is moderator or above, auto-approve
|
||||
if self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
try:
|
||||
self.object = form.save()
|
||||
submission.object_id = self.object.id
|
||||
submission.status = 'APPROVED'
|
||||
submission.handled_by = self.request.user
|
||||
submission.save()
|
||||
Args:
|
||||
form: The form to process
|
||||
cleaned_data: The cleaned form data
|
||||
|
||||
# Handle photo uploads
|
||||
photos = self.request.FILES.getlist('photos')
|
||||
uploaded_count = 0
|
||||
for photo_file in photos:
|
||||
try:
|
||||
Photo.objects.create(
|
||||
image=photo_file,
|
||||
uploaded_by=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Ride),
|
||||
object_id=self.object.id
|
||||
)
|
||||
uploaded_count += 1
|
||||
except Exception as e:
|
||||
messages.error(self.request, f"Error uploading photo {photo_file.name}: {str(e)}")
|
||||
Returns:
|
||||
HttpResponseRedirect to appropriate URL
|
||||
"""
|
||||
submission = create_edit_submission(self.request, "CREATE", cleaned_data)
|
||||
|
||||
if is_privileged_user(self.request.user):
|
||||
success, error_msg = handle_privileged_save(self.request, form, submission)
|
||||
if success:
|
||||
self.object = form.instance
|
||||
uploaded_count = handle_photo_uploads(self.request, self.object)
|
||||
messages.success(
|
||||
self.request,
|
||||
f"Successfully created {self.object.name} at {self.park.name}. "
|
||||
f"Added {uploaded_count} photo(s)."
|
||||
f"Added {uploaded_count} photo(s).",
|
||||
)
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
except Exception as e:
|
||||
messages.error(
|
||||
self.request,
|
||||
f"Error creating ride: {str(e)}. Please check your input and try again."
|
||||
)
|
||||
return self.form_invalid(form)
|
||||
|
||||
else:
|
||||
if error_msg: # Only add error message if there is one
|
||||
messages.error(self.request, error_msg)
|
||||
return cast(HttpResponseRedirect, self.form_invalid(form))
|
||||
|
||||
messages.success(
|
||||
self.request,
|
||||
"Your ride submission has been sent for review. "
|
||||
"You will be notified when it is approved."
|
||||
"You will be notified when it is approved.",
|
||||
)
|
||||
return HttpResponseRedirect(
|
||||
reverse("parks:rides:ride_list", kwargs={"park_slug": self.park.slug})
|
||||
)
|
||||
return HttpResponseRedirect(reverse('parks:rides:ride_list', kwargs={'park_slug': self.park.slug}))
|
||||
|
||||
def form_invalid(self, form):
|
||||
messages.error(
|
||||
self.request,
|
||||
"Please correct the errors below. Required fields are marked with an asterisk (*)."
|
||||
)
|
||||
for field, errors in form.errors.items():
|
||||
for error in errors:
|
||||
messages.error(self.request, f"{field}: {error}")
|
||||
def form_valid(self, form: RideForm) -> HttpResponseRedirect:
|
||||
form.instance.park = self.park
|
||||
cleaned_data = prepare_form_data(form.cleaned_data, self.park)
|
||||
return self.handle_submission(form, cleaned_data)
|
||||
|
||||
def form_invalid(self, form: RideForm) -> Union[HttpResponse, HttpResponseRedirect]:
|
||||
"""Handle invalid form submission.
|
||||
|
||||
Args:
|
||||
form: The invalid form
|
||||
|
||||
Returns:
|
||||
Response with error messages
|
||||
"""
|
||||
handle_form_errors(self.request, form)
|
||||
return super().form_invalid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('parks:rides:ride_detail', kwargs={
|
||||
'park_slug': self.park.slug,
|
||||
'ride_slug': self.object.slug
|
||||
})
|
||||
def get_success_url(self) -> str:
|
||||
return reverse(
|
||||
"parks:rides:ride_detail",
|
||||
kwargs={"park_slug": self.park.slug, "ride_slug": self.object.slug},
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['park'] = self.park
|
||||
context["park"] = self.park
|
||||
return context
|
||||
|
||||
|
||||
class RideUpdateView(LoginRequiredMixin, UpdateView):
|
||||
model = Ride
|
||||
form_class = RideForm
|
||||
template_name = 'rides/ride_form.html'
|
||||
slug_url_kwarg = 'ride_slug'
|
||||
template_name = "rides/ride_form.html"
|
||||
slug_url_kwarg = "ride_slug"
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
def setup(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
|
||||
super().setup(request, *args, **kwargs)
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs['park_slug'])
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs["park_slug"])
|
||||
|
||||
def get_form_kwargs(self):
|
||||
def get_form_kwargs(self) -> Dict[str, Any]:
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['park'] = self.park
|
||||
kwargs["park"] = self.park
|
||||
return kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['park'] = self.park
|
||||
context['is_edit'] = True
|
||||
context["park"] = self.park
|
||||
context["is_edit"] = True
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
cleaned_data = form.cleaned_data.copy()
|
||||
cleaned_data['park'] = self.park.id
|
||||
# Convert model instances to IDs for JSON serialization
|
||||
if cleaned_data.get('park_area'):
|
||||
cleaned_data['park_area'] = cleaned_data['park_area'].id
|
||||
if cleaned_data.get('manufacturer'):
|
||||
cleaned_data['manufacturer'] = cleaned_data['manufacturer'].id
|
||||
def handle_submission(
|
||||
self, form: RideForm, cleaned_data: Dict[str, Any]
|
||||
) -> HttpResponseRedirect:
|
||||
"""Handle the form submission.
|
||||
|
||||
# Create submission record
|
||||
submission = EditSubmission.objects.create(
|
||||
user=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Ride),
|
||||
object_id=self.object.id,
|
||||
submission_type='EDIT',
|
||||
changes=cleaned_data,
|
||||
reason=self.request.POST.get('reason', ''),
|
||||
source=self.request.POST.get('source', '')
|
||||
Args:
|
||||
form: The form to process
|
||||
cleaned_data: The cleaned form data
|
||||
|
||||
Returns:
|
||||
HttpResponseRedirect to appropriate URL
|
||||
"""
|
||||
submission = create_edit_submission(
|
||||
self.request, "EDIT", cleaned_data, self.object.pk
|
||||
)
|
||||
|
||||
# If user is moderator or above, auto-approve
|
||||
if self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
try:
|
||||
self.object = form.save()
|
||||
submission.status = 'APPROVED'
|
||||
submission.handled_by = self.request.user
|
||||
submission.save()
|
||||
|
||||
# Handle photo uploads
|
||||
photos = self.request.FILES.getlist('photos')
|
||||
uploaded_count = 0
|
||||
for photo_file in photos:
|
||||
try:
|
||||
Photo.objects.create(
|
||||
image=photo_file,
|
||||
uploaded_by=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Ride),
|
||||
object_id=self.object.id
|
||||
)
|
||||
uploaded_count += 1
|
||||
except Exception as e:
|
||||
messages.error(self.request, f"Error uploading photo {photo_file.name}: {str(e)}")
|
||||
|
||||
if is_privileged_user(self.request.user):
|
||||
success, error_msg = handle_privileged_save(self.request, form, submission)
|
||||
if success:
|
||||
self.object = form.instance
|
||||
uploaded_count = handle_photo_uploads(self.request, self.object)
|
||||
messages.success(
|
||||
self.request,
|
||||
f"Successfully updated {self.object.name}. "
|
||||
f"Added {uploaded_count} new photo(s)."
|
||||
f"Added {uploaded_count} new photo(s).",
|
||||
)
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
except Exception as e:
|
||||
messages.error(
|
||||
self.request,
|
||||
f"Error updating ride: {str(e)}. Please check your input and try again."
|
||||
)
|
||||
return self.form_invalid(form)
|
||||
|
||||
else:
|
||||
if error_msg: # Only add error message if there is one
|
||||
messages.error(self.request, error_msg)
|
||||
return cast(HttpResponseRedirect, self.form_invalid(form))
|
||||
|
||||
messages.success(
|
||||
self.request,
|
||||
f"Your changes to {self.object.name} have been sent for review. "
|
||||
"You will be notified when they are approved."
|
||||
"You will be notified when they are approved.",
|
||||
)
|
||||
return HttpResponseRedirect(
|
||||
reverse(
|
||||
"parks:rides:ride_detail",
|
||||
kwargs={"park_slug": self.park.slug, "ride_slug": self.object.slug},
|
||||
)
|
||||
)
|
||||
return HttpResponseRedirect(reverse('parks:rides:ride_detail', kwargs={
|
||||
'park_slug': self.park.slug,
|
||||
'ride_slug': self.object.slug
|
||||
}))
|
||||
|
||||
def form_invalid(self, form):
|
||||
messages.error(
|
||||
self.request,
|
||||
"Please correct the errors below. Required fields are marked with an asterisk (*)."
|
||||
)
|
||||
for field, errors in form.errors.items():
|
||||
for error in errors:
|
||||
messages.error(self.request, f"{field}: {error}")
|
||||
def form_valid(self, form: RideForm) -> HttpResponseRedirect:
|
||||
cleaned_data = prepare_form_data(form.cleaned_data, self.park)
|
||||
return self.handle_submission(form, cleaned_data)
|
||||
|
||||
def form_invalid(self, form: RideForm) -> Union[HttpResponse, HttpResponseRedirect]:
|
||||
"""Handle invalid form submission.
|
||||
|
||||
Args:
|
||||
form: The invalid form
|
||||
|
||||
Returns:
|
||||
Response with error messages
|
||||
"""
|
||||
handle_form_errors(self.request, form)
|
||||
return super().form_invalid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('parks:rides:ride_detail', kwargs={
|
||||
'park_slug': self.park.slug,
|
||||
'ride_slug': self.object.slug
|
||||
})
|
||||
def get_success_url(self) -> str:
|
||||
return reverse(
|
||||
"parks:rides:ride_detail",
|
||||
kwargs={"park_slug": self.park.slug, "ride_slug": self.object.slug},
|
||||
)
|
||||
|
||||
class RideDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin, DetailView):
|
||||
|
||||
class RideDetailView(
|
||||
SlugRedirectMixin,
|
||||
EditSubmissionMixin,
|
||||
PhotoSubmissionMixin,
|
||||
HistoryMixin,
|
||||
DetailView,
|
||||
):
|
||||
model = Ride
|
||||
template_name = 'rides/ride_detail.html'
|
||||
context_object_name = 'ride'
|
||||
slug_url_kwarg = 'ride_slug'
|
||||
template_name = "rides/ride_detail.html"
|
||||
context_object_name = "ride"
|
||||
slug_url_kwarg = "ride_slug"
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
if queryset is None:
|
||||
queryset = self.get_queryset()
|
||||
park_slug = self.kwargs.get('park_slug')
|
||||
ride_slug = self.kwargs.get('ride_slug')
|
||||
# Try to get by current or historical slug
|
||||
obj, is_old_slug = self.model.get_by_slug(ride_slug)
|
||||
park_slug = self.kwargs.get("park_slug")
|
||||
ride_slug = self.kwargs.get("ride_slug")
|
||||
obj, is_old_slug = self.model.get_by_slug(ride_slug) # type: ignore[attr-defined]
|
||||
if obj.park.slug != park_slug:
|
||||
raise self.model.DoesNotExist("Park slug doesn't match")
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.object.category == 'RC':
|
||||
context['coaster_stats'] = RollerCoasterStats.objects.filter(ride=self.object).first()
|
||||
if self.object.category == "RC":
|
||||
context["coaster_stats"] = RollerCoasterStats.objects.filter(
|
||||
ride=self.object
|
||||
).first()
|
||||
return context
|
||||
|
||||
def get_redirect_url_pattern(self):
|
||||
return 'parks:rides:ride_detail'
|
||||
def get_redirect_url_pattern(self) -> str:
|
||||
return "parks:rides:ride_detail"
|
||||
|
||||
def get_redirect_url_kwargs(self) -> Dict[str, Any]:
|
||||
return {"park_slug": self.object.park.slug, "ride_slug": self.object.slug}
|
||||
|
||||
def get_redirect_url_kwargs(self):
|
||||
return {
|
||||
'park_slug': self.object.park.slug,
|
||||
'ride_slug': self.object.slug
|
||||
}
|
||||
|
||||
class RideListView(ListView):
|
||||
model = Ride
|
||||
template_name = 'rides/ride_list.html'
|
||||
context_object_name = 'rides'
|
||||
template_name = "rides/ride_list.html"
|
||||
context_object_name = "rides"
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
def setup(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
|
||||
super().setup(request, *args, **kwargs)
|
||||
self.park = None
|
||||
if 'park_slug' in self.kwargs:
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs['park_slug'])
|
||||
if "park_slug" in self.kwargs:
|
||||
self.park = get_object_or_404(Park, slug=self.kwargs["park_slug"])
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Ride.objects.select_related('park', 'coaster_stats', 'manufacturer').prefetch_related('photos')
|
||||
|
||||
# Filter by park if viewing park-specific rides
|
||||
queryset = Ride.objects.select_related(
|
||||
"park", "coaster_stats", "manufacturer"
|
||||
).prefetch_related("photos")
|
||||
|
||||
if self.park:
|
||||
queryset = queryset.filter(park=self.park)
|
||||
|
||||
search = self.request.GET.get('search', '').strip() or None
|
||||
category = self.request.GET.get('category', '').strip() or None
|
||||
status = self.request.GET.get('status', '').strip() or None
|
||||
manufacturer = self.request.GET.get('manufacturer', '').strip() or None
|
||||
|
||||
|
||||
search = self.request.GET.get("search", "").strip() or None
|
||||
category = self.request.GET.get("category", "").strip() or None
|
||||
status = self.request.GET.get("status", "").strip() or None
|
||||
manufacturer = self.request.GET.get("manufacturer", "").strip() or None
|
||||
|
||||
if search:
|
||||
if self.park:
|
||||
queryset = queryset.filter(name__icontains=search)
|
||||
else:
|
||||
queryset = queryset.filter(
|
||||
Q(name__icontains=search) |
|
||||
Q(park__name__icontains=search)
|
||||
Q(name__icontains=search) | Q(park__name__icontains=search)
|
||||
)
|
||||
if category:
|
||||
queryset = queryset.filter(category=category)
|
||||
@@ -351,37 +472,34 @@ class RideListView(ListView):
|
||||
queryset = queryset.filter(status=status)
|
||||
if manufacturer:
|
||||
queryset = queryset.exclude(manufacturer__isnull=True)
|
||||
|
||||
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['park'] = self.park
|
||||
context["park"] = self.park
|
||||
|
||||
# Get manufacturers for the filter dropdown
|
||||
manufacturer_query = Ride.objects
|
||||
if self.park:
|
||||
manufacturer_query = manufacturer_query.filter(park=self.park)
|
||||
|
||||
context['manufacturers'] = list(
|
||||
|
||||
context["manufacturers"] = list(
|
||||
manufacturer_query.exclude(manufacturer__isnull=True)
|
||||
.values_list('manufacturer__name', flat=True)
|
||||
.distinct().order_by('manufacturer__name')
|
||||
.values_list("manufacturer__name", flat=True)
|
||||
.distinct()
|
||||
.order_by("manufacturer__name")
|
||||
)
|
||||
|
||||
# Add current filter values to context
|
||||
context['current_filters'] = {
|
||||
'search': self.request.GET.get('search', ''),
|
||||
'category': self.request.GET.get('category', ''),
|
||||
'status': self.request.GET.get('status', ''),
|
||||
'manufacturer': self.request.GET.get('manufacturer', '')
|
||||
context["current_filters"] = {
|
||||
"search": self.request.GET.get("search", ""),
|
||||
"category": self.request.GET.get("category", ""),
|
||||
"status": self.request.GET.get("status", ""),
|
||||
"manufacturer": self.request.GET.get("manufacturer", ""),
|
||||
}
|
||||
|
||||
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
# Check if this is an HTMX request
|
||||
if request.htmx:
|
||||
# If it is, return just the rides list partial
|
||||
self.template_name = 'rides/partials/ride_list.html'
|
||||
def get(self, request: HttpRequest, *args: Any, **kwargs: Any):
|
||||
if getattr(request, "htmx", False): # type: ignore[attr-defined]
|
||||
self.template_name = "rides/partials/ride_list.html"
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user