# Data Documentation ## Database Schema ### Core Models #### Parks ```sql CREATE TABLE parks_park ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, slug VARCHAR(255) UNIQUE NOT NULL, description TEXT, status VARCHAR(20) DEFAULT 'OPERATING', opening_date DATE, closing_date DATE, operating_season VARCHAR(255), size_acres DECIMAL(10,2), website VARCHAR(200), average_rating DECIMAL(3,2), ride_count INTEGER, coaster_count INTEGER, owner_id INTEGER REFERENCES companies_company(id), created_at TIMESTAMP, updated_at TIMESTAMP ); ``` #### Rides ```sql CREATE TABLE rides_ride ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(20), park_id INTEGER REFERENCES parks_park(id), area_id INTEGER REFERENCES parks_parkarea(id), manufacturer_id INTEGER REFERENCES companies_company(id), designer_id INTEGER REFERENCES designers_designer(id), opening_date DATE, closing_date DATE, height_requirement INTEGER, ride_type VARCHAR(50), thrill_rating INTEGER, created_at TIMESTAMP, updated_at TIMESTAMP, UNIQUE(park_id, slug) ); ``` #### Reviews ```sql CREATE TABLE reviews_review ( id SERIAL PRIMARY KEY, content TEXT NOT NULL, rating DECIMAL(3,2), status VARCHAR(20), author_id INTEGER REFERENCES auth_user(id), content_type_id INTEGER REFERENCES django_content_type(id), object_id INTEGER, created_at TIMESTAMP, updated_at TIMESTAMP ); ``` ### Entity Relationships ```mermaid erDiagram Park ||--o{ ParkArea : "contains" Park ||--o{ Ride : "has" Park ||--o{ Photo : "has" Park ||--o{ Review : "receives" ParkArea ||--o{ Ride : "contains" Ride ||--o{ Photo : "has" Ride ||--o{ Review : "receives" Company ||--o{ Park : "owns" Company ||--o{ Ride : "manufactures" Designer ||--o{ Ride : "designs" User ||--o{ Review : "writes" ``` ## Data Models ### Content Models #### Park Model - Core information about theme parks - Location data through GenericRelation - Media attachments - Historical tracking - Owner relationship #### Ride Model - Technical specifications - Park and area relationships - Manufacturer and designer links - Operation status tracking - Safety requirements #### Review Model - Generic foreign key for flexibility - Rating system - Media attachments - Moderation status - Author tracking ### Supporting Models #### Location Model ```python class Location(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() address = models.CharField(max_length=255) city = models.CharField(max_length=100) state = models.CharField(max_length=100) country = models.CharField(max_length=100) postal_code = models.CharField(max_length=20) latitude = models.DecimalField(max_digits=9, decimal_places=6) longitude = models.DecimalField(max_digits=9, decimal_places=6) ``` #### Media Model ```python class Photo(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() file = models.ImageField(upload_to='photos/') caption = models.CharField(max_length=255) taken_at = models.DateTimeField(null=True) uploaded_at = models.DateTimeField(auto_now_add=True) ``` ## Storage Strategies ### Database Storage #### PostgreSQL Configuration ```python DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'thrillwiki', 'CONN_MAX_AGE': 60, 'OPTIONS': { 'client_encoding': 'UTF8', }, } } ``` #### Indexing Strategy ```sql -- Performance indexes CREATE INDEX idx_park_slug ON parks_park(slug); CREATE INDEX idx_ride_slug ON rides_ride(slug); CREATE INDEX idx_review_content_type ON reviews_review(content_type_id, object_id); ``` ### File Storage #### Media Storage ```python # Media storage configuration MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/' # File upload handlers FILE_UPLOAD_HANDLERS = [ 'django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler', ] ``` #### Directory Structure ``` media/ ├── photos/ │ ├── parks/ │ ├── rides/ │ └── reviews/ ├── avatars/ └── documents/ ``` ### Caching Strategy #### Cache Configuration ```python CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.redis.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379/1', 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', } } } ``` #### Cache Keys ```python # Cache key patterns CACHE_KEYS = { 'park_detail': 'park:{slug}', 'ride_list': 'park:{park_slug}:rides', 'review_count': 'content:{type}:{id}:reviews', } ``` ## Data Migration ### Migration Strategy 1. Schema migrations via Django 2. Data migrations for model changes 3. Content migrations for large updates ### Example Migration ```python # migrations/0002_add_park_status.py from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('parks', '0001_initial'), ] operations = [ migrations.AddField( model_name='park', name='status', field=models.CharField( max_length=20, choices=[ ('OPERATING', 'Operating'), ('CLOSED', 'Closed'), ], default='OPERATING' ), ), ] ``` ## Data Protection ### Backup Strategy 1. Daily database backups 2. Media files backup 3. Retention policy management ### Backup Configuration ```python # backup settings BACKUP_ROOT = os.path.join(BASE_DIR, 'backups') BACKUP_RETENTION_DAYS = 30 BACKUP_COMPRESSION = True ``` ## Data Validation ### Model Validation ```python class Park(models.Model): def clean(self): if self.closing_date and self.opening_date: if self.closing_date < self.opening_date: raise ValidationError({ 'closing_date': 'Closing date cannot be before opening date' }) ``` ### Form Validation ```python class RideForm(forms.ModelForm): def clean_height_requirement(self): height = self.cleaned_data['height_requirement'] if height and height < 0: raise forms.ValidationError('Height requirement cannot be negative') return height ``` ## Data Access Patterns ### QuerySet Optimization ```python # Optimized query pattern Park.objects.select_related('owner')\ .prefetch_related('rides', 'areas')\ .filter(status='OPERATING') ``` ### Caching Pattern ```python def get_park_detail(slug): cache_key = f'park:{slug}' park = cache.get(cache_key) if not park: park = Park.objects.get(slug=slug) cache.set(cache_key, park, timeout=3600) return park ``` ## Monitoring and Metrics ### Database Metrics - Query performance - Cache hit rates - Storage usage - Connection pool status ### Collection Configuration ```python LOGGING = { 'handlers': { 'db_log': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', 'filename': 'logs/db.log', }, }, }