Files
thrillwiki_django_no_react/backend/apps/parks/models/companies.py
pacnpal 8069589b8a feat: Complete Phase 5 of Django Unicorn refactoring for park detail templates
- Refactored park detail template from HTMX/Alpine.js to Django Unicorn component
- Achieved ~97% reduction in template complexity
- Created ParkDetailView component with optimized data loading and reactive features
- Developed a responsive reactive template for park details
- Implemented server-side state management and reactive event handlers
- Enhanced performance with optimized database queries and loading states
- Comprehensive error handling and user experience improvements

docs: Update Django Unicorn refactoring plan with completed components and phases

- Documented installation and configuration of Django Unicorn
- Detailed completed work on park search component and refactoring strategy
- Outlined planned refactoring phases for future components
- Provided examples of component structure and usage

feat: Implement parks rides endpoint with comprehensive features

- Developed API endpoint GET /api/v1/parks/{park_slug}/rides/ for paginated ride listings
- Included filtering capabilities for categories and statuses
- Optimized database queries with select_related and prefetch_related
- Implemented serializer for comprehensive ride data output
- Added complete API documentation for frontend integration
2025-09-02 22:58:11 -04:00

148 lines
4.7 KiB
Python

from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.utils.text import slugify
from apps.core.models import TrackedModel
import pghistory
@pghistory.track()
class Company(TrackedModel):
# Import managers
from ..managers import CompanyManager
objects = CompanyManager()
class CompanyRole(models.TextChoices):
OPERATOR = "OPERATOR", "Park Operator"
PROPERTY_OWNER = "PROPERTY_OWNER", "Property Owner"
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True)
roles = ArrayField(
models.CharField(max_length=20, choices=CompanyRole.choices),
default=list,
blank=True,
)
description = models.TextField(blank=True)
website = models.URLField(blank=True)
# Operator-specific fields
founded_year = models.PositiveIntegerField(blank=True, null=True)
parks_count = models.IntegerField(default=0)
rides_count = models.IntegerField(default=0)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
@property
def url(self):
"""Generate the frontend URL for this company based on its roles."""
from config.django import base as settings
if "OPERATOR" in self.roles:
return f"{settings.FRONTEND_DOMAIN}/parks/operators/{self.slug}/"
elif "PROPERTY_OWNER" in self.roles:
return f"{settings.FRONTEND_DOMAIN}/parks/owners/{self.slug}/"
elif "MANUFACTURER" in self.roles:
return f"{settings.FRONTEND_DOMAIN}/rides/manufacturers/{self.slug}/"
elif "DESIGNER" in self.roles:
return f"{settings.FRONTEND_DOMAIN}/rides/designers/{self.slug}/"
else:
# Default fallback
return f"{settings.FRONTEND_DOMAIN}/companies/{self.slug}/"
def __str__(self):
return self.name
class Meta(TrackedModel.Meta):
app_label = "parks"
ordering = ["name"]
verbose_name_plural = "Companies"
@pghistory.track()
class CompanyHeadquarters(models.Model):
"""
Simple address storage for company headquarters without coordinate tracking.
Focus on human-readable location information for display purposes.
"""
# Relationships
company = models.OneToOneField(
"Company", on_delete=models.CASCADE, related_name="headquarters"
)
# Address Fields (No coordinates needed)
street_address = models.CharField(
max_length=255,
blank=True,
help_text="Mailing address if publicly available",
)
city = models.CharField(
max_length=100, db_index=True, help_text="Headquarters city"
)
state_province = models.CharField(
max_length=100,
blank=True,
db_index=True,
help_text="State/Province/Region",
)
country = models.CharField(
max_length=100,
default="USA",
db_index=True,
help_text="Country where headquarters is located",
)
postal_code = models.CharField(
max_length=20, blank=True, help_text="ZIP or postal code"
)
# Optional mailing address if different or more complete
mailing_address = models.TextField(
blank=True,
help_text="Complete mailing address if different from basic address",
)
# Metadata
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@property
def formatted_location(self):
"""Returns a formatted address string for display."""
components = []
if self.street_address:
components.append(self.street_address)
if self.city:
components.append(self.city)
if self.state_province:
components.append(self.state_province)
if self.postal_code:
components.append(self.postal_code)
if self.country and self.country != "USA":
components.append(self.country)
return ", ".join(components) if components else f"{self.city}, {self.country}"
@property
def location_display(self):
"""Simple city, state/country display for compact views."""
parts = [self.city]
if self.state_province:
parts.append(self.state_province)
elif self.country != "USA":
parts.append(self.country)
return ", ".join(parts) if parts else "Unknown Location"
def __str__(self):
return f"{self.company.name} Headquarters - {self.location_display}"
class Meta:
verbose_name = "Company Headquarters"
verbose_name_plural = "Company Headquarters"
ordering = ["company__name"]
indexes = [
models.Index(fields=["city", "country"]),
]