Skip to main content

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 in fkapi/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)
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.
URL to club logo
URLField
URL to dark mode logo
CountryField
Country where club is based

Indexes

  • name
  • country

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.
Model name uses Type_K (not Type) to avoid conflicts with Python’s type keyword and match legacy naming.
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, staff
  • preseason: Pre-season, temporary
  • training: Training
  • travel: Travel, polo
  • jacket: 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:
  1. Match kits appear first
  2. Outfield kits before goalkeeper kits within each category
  3. 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

  • name
  • country

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

Use select_related() for foreign key relationships (SQL JOIN):
Use prefetch_related() for many-to-many and reverse foreign key relationships:

Combined Example

Custom Fields

ColorField

Provided by django-colorfield package:
  • Stores hex color codes
  • Includes color picker widget in admin
  • Used in Color and Variation models

CountryField

Provided by django-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

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
PostgreSQL connection settings in settings.py:
  • CONN_MAX_AGE: 60 seconds
  • Keepalive settings for connection stability
  • Reduces connection overhead
Scraping operations use atomic transactions:

Model Methods

Type_K.categorize()

Automatically categorizes and sets ordering fields based on the type name:
This method is called automatically when new kit types are created during scraping.

Architecture

Learn about system architecture

Scraping

Understand how data is collected