Overview
FKApi uses Django ORM models to represent football kit data. The schema is designed to normalize data while maintaining query performance through strategic use of foreign keys, many-to-many relationships, and database indexes. All models are defined infkapi/core/models.py.
Entity Relationship Diagram
Core Models
Kit
The central model representing a football kit (jersey/uniform).CharField(100)
required
Kit name (indexed for search performance)
CharField(150)
required
URL-friendly identifier (unique). Allows special characters including Romanian characters (ăâîșț). Must match pattern:
[-a-zA-Z0-9_ăâîșțĂÂÎȘȚ]+CharField(20)
Original ID from FootballKitArchive.com for URL construction
ForeignKey(Club)
required
Club that owns this kit
ForeignKey(Season)
required
Season this kit was used
ManyToManyField(Competition)
Competitions this kit was used in
ForeignKey(Type_K)
required
Type of kit (Home, Away, Third, etc.)
ForeignKey(Brand)
required
Manufacturer/brand of the kit
URLField
required
URL to main kit image
DecimalField(3,2)
required
User rating (0.00-10.00)
URLField
Link to FootyHeadlines.com
DateTimeField
Last update time from source website
DateTimeField
Last update time in database (auto-updated)
ForeignKey(Color)
Primary color of the kit
ManyToManyField(Color)
Secondary colors of the kit
CharField(100)
Design description or pattern name
Indexes
Kit model has the following database indexes for query optimization:name(single field)team, season(composite)main_img_url(single field)web_updated(single field)last_updated(single field)rating(single field)
Club
Represents a football club/team.IntegerField
Original ID from footballkitarchive.com
CharField(500)
required
Club name (indexed for search performance)
CharField(150)
required
URL-friendly identifier (unique). Supports special characters like Romanian letters.
URLField
URL to club logo
URLField
URL to dark mode logo
CountryField
Country where club is based
Indexes
namecountry
Season
Represents a football season. Supports both single-year (“2024”) and two-year (“2023-24”) formats.CharField(9)
required
Full season identifier (unique). Examples: “2024”, “2023-24”, “1999-00”
CharField(4)
required
First year of the season (4-digit year)
CharField(4)
Second year of the season for two-year formats (4-digit year)
The scraper automatically handles various season format inputs including “23-24”, “2023-24”, “2023-2024” and normalizes them to the standard format.
Type_K
Represents the type of kit with categorization and ordering.CharField(100)
required
Type name (e.g., “Home”, “Away”, “Third”, “GK Home”)
CharField(20)
required
Category for organization. Choices:
match: Game kits (default)prematch: Pre-match, bench, warm-up, staffpreseason: Pre-season, temporarytraining: Trainingtravel: Travel, polojacket: Jackets (anthem, rain, windbreaker, track, vest)
IntegerField
required
Order of category (1-6):
- 1 = match
- 2 = prematch
- 3 = preseason
- 4 = training
- 5 = travel
- 6 = jacket
IntegerField
default:"999"
Priority within category (lower = first). Non-GK items come before GK items.
BooleanField
default:"False"
True if this is a goalkeeper kit (GK, Goalkeeper, Portero)
Ordering
Default ordering:['category_order', 'is_goalkeeper', 'order_priority', 'name']
This ensures:
- Match kits appear first
- Outfield kits before goalkeeper kits within each category
- Standard types (Home, Away, Third) before special types
Indexes
- Composite:
(category_order, is_goalkeeper, order_priority) - Composite:
(category, is_goalkeeper, order_priority)
Brand
Represents a kit manufacturer/brand.CharField(100)
required
Brand name (indexed)
SlugField(150)
required
URL-friendly identifier (unique)
URLField
URL to brand logo
URLField
URL to dark mode logo
Index
name
Competition
Represents a football competition.CharField(100)
required
Competition name (indexed)
SlugField(150)
required
URL-friendly identifier (unique)
URLField
URL to competition logo
URLField
URL to dark mode logo
CountryField
Country where competition is based
Indexes
namecountry
Color
Represents a color used in kit designs.CharField(100)
required
Name of the color (e.g., “Red”, “Blue”, “Navy”)
ColorField
default:"#FF0000"
Hex color code (e.g., “#FF0000” for red)
Variation
Represents a color variation (shade) of a parent color.CharField(100)
required
Name of the variation (e.g., “Light Blue”, “Dark Red”)
ForeignKey(Color)
required
Parent color this variation belongs to
ColorField
default:"#FF0000"
Hex color code for the variation
IntegerField
default:"0"
Red component (0-255)
IntegerField
default:"0"
Green component (0-255)
IntegerField
default:"0"
Blue component (0-255)
Relationships
One-to-Many Relationships
Club → Kit
One club has many kits
Season → Kit
One season has many kits
Brand → Kit
One brand has many kits
Type_K → Kit
One type has many kits
Color → Variation
One color has many variations
Many-to-Many Relationships
Kit ↔ Competition
Kits can be used in multiple competitions
Kit ↔ Color (secondary)
Kits can have multiple secondary colors
Query Optimization
select_related() vs prefetch_related()
Useselect_related() for foreign key relationships (SQL JOIN):
prefetch_related() for many-to-many and reverse foreign key relationships:
Combined Example
Custom Fields
ColorField
Provided bydjango-colorfield package:
- Stores hex color codes
- Includes color picker widget in admin
- Used in Color and Variation models
CountryField
Provided bydjango-countries package:
- Stores ISO 3166-1 country codes
- Provides country name display
- Used in Club and Competition models
Custom Slug Field
Both Kit and Club use custom slug validators that allow special characters:- Pattern:
[-a-zA-Z0-9_ăâîșțĂÂÎȘȚ]+ - Supports Romanian characters
- More permissive than Django’s default SlugField
Database Considerations
Indexes
Indexes
Strategic indexes improve query performance:
- Single-field indexes on frequently searched columns (name, slug)
- Composite indexes for common filter combinations (team+season)
- Category ordering indexes for Type_K sorting
Connection Pooling
Connection Pooling
PostgreSQL connection settings in
settings.py:CONN_MAX_AGE: 60 seconds- Keepalive settings for connection stability
- Reduces connection overhead
Transactions
Transactions
Scraping operations use atomic transactions:
Model Methods
Type_K.categorize()
Automatically categorizes and sets ordering fields based on the type name:Related Documentation
Architecture
Learn about system architecture
Scraping
Understand how data is collected