Add search app configuration, views, and templates for advanced filtering functionality

This commit is contained in:
pacnpal
2025-02-12 12:58:04 -05:00
parent 62723d0e33
commit af57592496
14 changed files with 1047 additions and 3 deletions

137
search/examples.py Normal file
View File

@@ -0,0 +1,137 @@
"""
Examples of how to use the search/filter system in different contexts.
These are example implementations - DO NOT import or use this file directly.
"""
from django.views.generic import ListView
from django_filters import CharFilter, ChoiceFilter, NumberFilter, DateFromToRangeFilter
from django.db.models import Q
from .mixins import HTMXFilterableMixin
from .filters import LocationFilterMixin, RatingFilterMixin, DateRangeFilterMixin, create_model_filter
# Example 1: Basic List View with Filtering
"""
class RideListView(HTMXFilterableMixin, ListView):
model = Ride
template_name = "rides/ride_list.html"
paginate_by = 20
# Define search fields for text search
search_fields = ['name', 'description', 'manufacturer__name']
# Add any model-specific filters
additional_filters = {
'category': ChoiceFilter(choices=Ride.CATEGORY_CHOICES),
'manufacturer': ModelChoiceFilter(queryset=Manufacturer.objects.all()),
'status': ChoiceFilter(choices=Ride.STATUS_CHOICES),
}
def get_queryset(self):
return super().get_queryset().select_related('park', 'manufacturer')
"""
# Example 2: Using create_model_filter for Dynamic Filter Creation
"""
# Create a filter for Company model
CompanyFilter = create_model_filter(
model=Company,
search_fields=['name', 'description', 'headquarters'],
mixins=[LocationFilterMixin, DateRangeFilterMixin],
additional_filters={
'min_parks': NumberFilter(
field_name='parks__count',
lookup_expr='gte',
label='Minimum Parks'
),
}
)
class CompanyListView(HTMXFilterableMixin, ListView):
model = Company
filter_class = CompanyFilter
template_name = "companies/company_list.html"
"""
# Example 3: Custom Filter Implementation
"""
class ManufacturerFilter(FilterSet):
search = CharFilter(method='filter_search')
country = ChoiceFilter(choices=COUNTRY_CHOICES)
founded_date = DateFromToRangeFilter()
min_rides = NumberFilter(field_name='rides__count', lookup_expr='gte')
class Meta:
model = Manufacturer
fields = {
'status': ['exact'],
'type': ['exact', 'in'],
}
def filter_search(self, queryset, name, value):
if not value:
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(description__icontains=value) |
Q(rides__name__icontains=value)
).distinct()
"""
# Example 4: Custom Template Implementation
"""
{# templates/search/partials/ride_results.html #}
<div class="divide-y">
{% for ride in object_list %}
<div class="p-4 flex items-start space-x-4">
{% if ride.photos.exists %}
<img src="{{ ride.photos.first.image.url }}"
alt="{{ ride.name }}"
class="w-24 h-24 object-cover rounded-lg">
{% endif %}
<div class="flex-1">
<h3 class="text-lg font-semibold">
<a href="{{ ride.get_absolute_url }}">{{ ride.name }}</a>
</h3>
<div class="mt-1 text-sm text-gray-500">
{{ ride.get_category_display }} at
<a href="{{ ride.park.get_absolute_url }}"
class="text-blue-600 hover:underline">
{{ ride.park.name }}
</a>
</div>
{% if ride.manufacturer %}
<div class="mt-1 text-sm">
Built by {{ ride.manufacturer.name }}
</div>
{% endif %}
<div class="mt-2 flex flex-wrap gap-2">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ ride.get_status_color }}">
{{ ride.get_status_display }}
</span>
{% if ride.opening_date %}
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">
Opened {{ ride.opening_date|date:"Y" }}
</span>
{% endif %}
{% if ride.average_rating %}
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
{{ ride.average_rating }} ★
</span>
{% endif %}
</div>
</div>
</div>
{% empty %}
<div class="p-8 text-center text-gray-500">
No rides found matching your criteria
</div>
{% endfor %}
</div>
"""