mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 06:51:08 -05:00
Implement hybrid filtering strategy for parks and rides
- Added comprehensive documentation for hybrid filtering implementation, including architecture, API endpoints, performance characteristics, and usage examples. - Developed a hybrid pagination and client-side filtering recommendation, detailing server-side responsibilities and client-side logic. - Created a test script for hybrid filtering endpoints, covering various test cases including basic filtering, search functionality, pagination, and edge cases.
This commit is contained in:
131
docs/frontend.md
131
docs/frontend.md
@@ -319,7 +319,136 @@ The moderation system provides comprehensive content moderation, user management
|
||||
|
||||
## Rides API
|
||||
|
||||
### Rides Listing
|
||||
### Hybrid Rides Filtering (Recommended)
|
||||
|
||||
The hybrid filtering system automatically chooses between client-side and server-side filtering based on data size for optimal performance.
|
||||
|
||||
#### Main Hybrid Endpoint
|
||||
- **GET** `/api/v1/rides/hybrid/`
|
||||
- **Description**: Intelligent ride filtering with automatic strategy selection
|
||||
- **Strategy Selection**:
|
||||
- ≤200 total records: Client-side filtering (loads all data for frontend filtering)
|
||||
- >200 total records: Server-side filtering (database filtering with pagination)
|
||||
- **Query Parameters** (25+ comprehensive filtering options):
|
||||
- `search` (string): Full-text search across ride names, descriptions, parks, and related data
|
||||
- `park_slug` (string): Filter by park slug
|
||||
- `park_id` (int): Filter by park ID
|
||||
- `categories` (string): Filter by ride categories (comma-separated): RC,DR,FR,WR,TR,OT
|
||||
- `statuses` (string): Filter by ride statuses (comma-separated)
|
||||
- `manufacturer_ids` (string): Filter by manufacturer IDs (comma-separated)
|
||||
- `designer_ids` (string): Filter by designer IDs (comma-separated)
|
||||
- `ride_model_ids` (string): Filter by ride model IDs (comma-separated)
|
||||
- `opening_year` (int): Filter by specific opening year
|
||||
- `min_opening_year` (int): Filter by minimum opening year
|
||||
- `max_opening_year` (int): Filter by maximum opening year
|
||||
- `min_rating` (number): Filter by minimum average rating (1-10)
|
||||
- `max_rating` (number): Filter by maximum average rating (1-10)
|
||||
- `min_height_requirement` (int): Filter by minimum height requirement in inches
|
||||
- `max_height_requirement` (int): Filter by maximum height requirement in inches
|
||||
- `min_capacity` (int): Filter by minimum hourly capacity
|
||||
- `max_capacity` (int): Filter by maximum hourly capacity
|
||||
- `roller_coaster_types` (string): Filter by roller coaster types (comma-separated)
|
||||
- `track_materials` (string): Filter by track materials (comma-separated): STEEL,WOOD,HYBRID
|
||||
- `launch_types` (string): Filter by launch types (comma-separated)
|
||||
- `min_height_ft` (number): Filter by minimum roller coaster height in feet
|
||||
- `max_height_ft` (number): Filter by maximum roller coaster height in feet
|
||||
- `min_speed_mph` (number): Filter by minimum roller coaster speed in mph
|
||||
- `max_speed_mph` (number): Filter by maximum roller coaster speed in mph
|
||||
- `min_inversions` (int): Filter by minimum number of inversions
|
||||
- `max_inversions` (int): Filter by maximum number of inversions
|
||||
- `has_inversions` (boolean): Filter rides with inversions (true) or without (false)
|
||||
- `ordering` (string): Order results by field (name, -name, opening_date, -opening_date, average_rating, -average_rating, etc.)
|
||||
|
||||
- **Response Format**:
|
||||
```typescript
|
||||
{
|
||||
strategy: 'client_side' | 'server_side',
|
||||
data: RideData[],
|
||||
total_count: number,
|
||||
has_more: boolean,
|
||||
filter_metadata: FilterMetadata
|
||||
}
|
||||
```
|
||||
|
||||
#### Progressive Loading
|
||||
- **GET** `/api/v1/rides/hybrid/progressive/`
|
||||
- **Description**: Load additional ride data for server-side filtering strategy
|
||||
- **Query Parameters**: Same as main hybrid endpoint plus:
|
||||
- `offset` (int, required): Number of records to skip for pagination
|
||||
- **Usage**: Only use when main endpoint returns `strategy: 'server_side'` and `has_more: true`
|
||||
|
||||
#### Filter Metadata
|
||||
- **GET** `/api/v1/rides/hybrid/filter-metadata/`
|
||||
- **Description**: Get comprehensive filter metadata for dynamic filter generation
|
||||
- **Returns**: Complete filter options including:
|
||||
- Static options (categories, statuses, roller coaster types, track materials, launch types)
|
||||
- Dynamic data (available parks, park areas, manufacturers, designers, ride models)
|
||||
- Ranges (rating, height requirements, capacity, opening years, roller coaster stats)
|
||||
- Boolean filters and ordering options
|
||||
- **Caching**: Results cached for 5 minutes, automatically invalidated on data changes
|
||||
|
||||
#### Frontend Implementation Example
|
||||
```typescript
|
||||
// Basic hybrid filtering
|
||||
const loadRides = async (filters = {}) => {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
// Add filters to params
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
if (Array.isArray(value)) {
|
||||
params.append(key, value.join(','));
|
||||
} else {
|
||||
params.append(key, value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const response = await fetch(`/api/v1/rides/hybrid/?${params}`, {
|
||||
headers: { 'Authorization': `Bearer ${accessToken}` }
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.strategy === 'client_side') {
|
||||
// All data loaded - implement client-side filtering
|
||||
return handleClientSideData(data);
|
||||
} else {
|
||||
// Server-side strategy - implement progressive loading
|
||||
return handleServerSideData(data);
|
||||
}
|
||||
};
|
||||
|
||||
// Progressive loading for server-side strategy
|
||||
const loadMoreRides = async (filters = {}, offset = 0) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('offset', offset.toString());
|
||||
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
if (Array.isArray(value)) {
|
||||
params.append(key, value.join(','));
|
||||
} else {
|
||||
params.append(key, value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const response = await fetch(`/api/v1/rides/hybrid/progressive/?${params}`, {
|
||||
headers: { 'Authorization': `Bearer ${accessToken}` }
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
};
|
||||
|
||||
// Load filter metadata for dynamic filters
|
||||
const loadFilterMetadata = async () => {
|
||||
const response = await fetch('/api/v1/rides/hybrid/filter-metadata/');
|
||||
return await response.json();
|
||||
};
|
||||
```
|
||||
|
||||
### Legacy Rides Listing
|
||||
- **GET** `/api/v1/rides/`
|
||||
- **Query Parameters**:
|
||||
- `search`: Search in ride names and descriptions
|
||||
|
||||
Reference in New Issue
Block a user