feat: Implement Phase 1.5 entity models (Park, Ride, Company, RideModel, Photo)

- Created Company model with location tracking, date precision, and CloudFlare Images
- Created RideModel model for manufacturer's ride models with specifications
- Created Park model with location, dates, operator, and cached statistics
- Created Ride model with comprehensive stats, manufacturer, and park relationship
- Created Photo model with CloudFlare Images integration and generic relations
- Added lifecycle hooks for auto-slug generation and count updates
- Created migrations and applied to database
- Registered all models in Django admin with detailed fieldsets
- Fixed admin autocomplete_fields to use raw_id_fields where needed
- All models inherit from VersionedModel for automatic version tracking
- Models include date precision tracking for opening/closing dates
- Added comprehensive indexes for query performance

Phase 1.5 complete - Entity models ready for API development
This commit is contained in:
pacnpal
2025-11-08 11:43:27 -05:00
parent 543d7bc9dc
commit 9c46ef8b03
17 changed files with 2326 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
"""
Django Admin configuration for entity models.
"""
from django.contrib import admin
from .models import Company, RideModel, Park, Ride
@admin.register(Company)
class CompanyAdmin(admin.ModelAdmin):
"""Admin interface for Company model."""
list_display = ['name', 'slug', 'location', 'park_count', 'ride_count', 'created', 'modified']
list_filter = ['company_types', 'founded_date']
search_fields = ['name', 'slug', 'description']
readonly_fields = ['id', 'created', 'modified', 'park_count', 'ride_count']
prepopulated_fields = {'slug': ('name',)}
fieldsets = (
('Basic Information', {
'fields': ('name', 'slug', 'description', 'company_types')
}),
('Location', {
'fields': ('location',)
}),
('Dates', {
'fields': (
'founded_date', 'founded_date_precision',
'closed_date', 'closed_date_precision'
)
}),
('Media', {
'fields': ('logo_image_id', 'logo_image_url', 'website')
}),
('Statistics', {
'fields': ('park_count', 'ride_count'),
'classes': ('collapse',)
}),
('System', {
'fields': ('id', 'created', 'modified'),
'classes': ('collapse',)
}),
)
@admin.register(RideModel)
class RideModelAdmin(admin.ModelAdmin):
"""Admin interface for RideModel model."""
list_display = ['name', 'manufacturer', 'model_type', 'installation_count', 'created', 'modified']
list_filter = ['model_type', 'manufacturer']
search_fields = ['name', 'slug', 'description', 'manufacturer__name']
readonly_fields = ['id', 'created', 'modified', 'installation_count']
prepopulated_fields = {'slug': ('name',)}
autocomplete_fields = ['manufacturer']
fieldsets = (
('Basic Information', {
'fields': ('name', 'slug', 'description', 'manufacturer', 'model_type')
}),
('Typical Specifications', {
'fields': ('typical_height', 'typical_speed', 'typical_capacity')
}),
('Media', {
'fields': ('image_id', 'image_url')
}),
('Statistics', {
'fields': ('installation_count',),
'classes': ('collapse',)
}),
('System', {
'fields': ('id', 'created', 'modified'),
'classes': ('collapse',)
}),
)
@admin.register(Park)
class ParkAdmin(admin.ModelAdmin):
"""Admin interface for Park model."""
list_display = ['name', 'location', 'park_type', 'status', 'ride_count', 'coaster_count', 'opening_date']
list_filter = ['park_type', 'status', 'operator', 'opening_date']
search_fields = ['name', 'slug', 'description', 'location__name']
readonly_fields = ['id', 'created', 'modified', 'ride_count', 'coaster_count']
prepopulated_fields = {'slug': ('name',)}
autocomplete_fields = ['operator']
raw_id_fields = ['location']
fieldsets = (
('Basic Information', {
'fields': ('name', 'slug', 'description', 'park_type', 'status')
}),
('Location', {
'fields': ('location', 'latitude', 'longitude')
}),
('Dates', {
'fields': (
'opening_date', 'opening_date_precision',
'closing_date', 'closing_date_precision'
)
}),
('Operator', {
'fields': ('operator',)
}),
('Media', {
'fields': (
'banner_image_id', 'banner_image_url',
'logo_image_id', 'logo_image_url',
'website'
)
}),
('Statistics', {
'fields': ('ride_count', 'coaster_count'),
'classes': ('collapse',)
}),
('Custom Data', {
'fields': ('custom_fields',),
'classes': ('collapse',)
}),
('System', {
'fields': ('id', 'created', 'modified'),
'classes': ('collapse',)
}),
)
@admin.register(Ride)
class RideAdmin(admin.ModelAdmin):
"""Admin interface for Ride model."""
list_display = ['name', 'park', 'ride_category', 'status', 'is_coaster', 'manufacturer', 'opening_date']
list_filter = ['ride_category', 'status', 'is_coaster', 'park', 'manufacturer', 'opening_date']
search_fields = ['name', 'slug', 'description', 'park__name', 'manufacturer__name']
readonly_fields = ['id', 'created', 'modified', 'is_coaster']
prepopulated_fields = {'slug': ('name',)}
autocomplete_fields = ['park', 'manufacturer', 'model']
fieldsets = (
('Basic Information', {
'fields': ('name', 'slug', 'description', 'park')
}),
('Classification', {
'fields': ('ride_category', 'ride_type', 'is_coaster', 'status')
}),
('Dates', {
'fields': (
'opening_date', 'opening_date_precision',
'closing_date', 'closing_date_precision'
)
}),
('Manufacturer', {
'fields': ('manufacturer', 'model')
}),
('Statistics', {
'fields': ('height', 'speed', 'length', 'duration', 'inversions', 'capacity')
}),
('Media', {
'fields': ('image_id', 'image_url')
}),
('Custom Data', {
'fields': ('custom_fields',),
'classes': ('collapse',)
}),
('System', {
'fields': ('id', 'created', 'modified'),
'classes': ('collapse',)
}),
)