Remove custom indexes from Twitch models

Eliminates explicit index definitions and db_index usage from Django models and migrations, relying on default indexes and constraints. This simplifies model definitions and migration files, reducing maintenance overhead and potential redundancy.
This commit is contained in:
Joakim Hellsén 2025-10-13 04:15:24 +02:00
commit eab379a028
2 changed files with 59 additions and 218 deletions

View file

@ -1,4 +1,4 @@
# Generated by Django 5.2.7 on 2025-10-13 00:00
# Generated by Django 5.2.7 on 2025-10-13 00:36
from __future__ import annotations
import django.db.models.deletion
@ -17,30 +17,6 @@ class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.CreateModel(
name="Game",
fields=[
("id", models.TextField(primary_key=True, serialize=False, verbose_name="Game ID")),
(
"slug",
models.TextField(
blank=True, db_index=True, default="", help_text="Short unique identifier for the game.", max_length=200, verbose_name="Slug"
),
),
("name", models.TextField(blank=True, db_index=True, default="", verbose_name="Name")),
("display_name", models.TextField(blank=True, db_index=True, default="", verbose_name="Display name")),
("box_art", models.URLField(blank=True, default="", max_length=500, verbose_name="Box art URL")),
(
"box_art_file",
models.FileField(blank=True, help_text="Locally cached box art image served from this site.", null=True, upload_to="games/box_art/"),
),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this game record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this game record was last updated.")),
],
options={
"ordering": ["display_name"],
},
),
migrations.CreateModel(
name="Channel",
fields=[
@ -48,27 +24,20 @@ class Migration(migrations.Migration):
"id",
models.TextField(help_text="The unique Twitch identifier for the channel.", primary_key=True, serialize=False, verbose_name="Channel ID"),
),
("name", models.TextField(db_index=True, help_text="The lowercase username of the channel.", verbose_name="Username")),
(
"display_name",
models.TextField(db_index=True, help_text="The display name of the channel (with proper capitalization).", verbose_name="Display Name"),
),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this channel record was created.")),
("name", models.TextField(help_text="The lowercase username of the channel.", verbose_name="Username")),
("display_name", models.TextField(help_text="The display name of the channel (with proper capitalization).", verbose_name="Display Name")),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this channel record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this channel record was last updated.")),
],
options={
"ordering": ["display_name"],
"indexes": [
models.Index(fields=["name"], name="twitch_chan_name_15d566_idx"),
models.Index(fields=["display_name"], name="twitch_chan_display_2bf213_idx"),
],
},
),
migrations.CreateModel(
name="DropBenefit",
fields=[
("id", models.TextField(help_text="Unique Twitch identifier for the benefit.", primary_key=True, serialize=False)),
("name", models.TextField(blank=True, db_index=True, default="N/A", help_text="Name of the drop benefit.")),
("name", models.TextField(blank=True, default="N/A", help_text="Name of the drop benefit.")),
("image_asset_url", models.URLField(blank=True, default="", help_text="URL to the benefit's image asset.", max_length=500)),
(
"image_file",
@ -76,27 +45,52 @@ class Migration(migrations.Migration):
),
(
"created_at",
models.DateTimeField(
db_index=True, help_text="Timestamp when the benefit was created. This is from Twitch API and not auto-generated.", null=True
),
models.DateTimeField(help_text="Timestamp when the benefit was created. This is from Twitch API and not auto-generated.", null=True),
),
("entitlement_limit", models.PositiveIntegerField(default=1, help_text="Maximum number of times this benefit can be earned.")),
("is_ios_available", models.BooleanField(default=False, help_text="Whether the benefit is available on iOS.")),
(
"distribution_type",
models.TextField(blank=True, db_index=True, default="", help_text="Type of distribution for this benefit.", max_length=50),
),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this benefit record was created.")),
("distribution_type", models.TextField(blank=True, default="", help_text="Type of distribution for this benefit.", max_length=50)),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this benefit record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this benefit record was last updated.")),
],
options={
"ordering": ["-created_at"],
"indexes": [
models.Index(fields=["name"], name="twitch_drop_name_7125ff_idx"),
models.Index(fields=["created_at"], name="twitch_drop_created_a3563e_idx"),
models.Index(fields=["distribution_type"], name="twitch_drop_distrib_08b224_idx"),
models.Index(condition=models.Q(("is_ios_available", True)), fields=["is_ios_available"], name="benefit_ios_available_idx"),
],
},
),
migrations.CreateModel(
name="Game",
fields=[
("id", models.TextField(primary_key=True, serialize=False, verbose_name="Game ID")),
("slug", models.TextField(blank=True, default="", help_text="Short unique identifier for the game.", max_length=200, verbose_name="Slug")),
("name", models.TextField(blank=True, default="", verbose_name="Name")),
("display_name", models.TextField(blank=True, default="", verbose_name="Display name")),
("box_art", models.URLField(blank=True, default="", max_length=500, verbose_name="Box art URL")),
(
"box_art_file",
models.FileField(blank=True, help_text="Locally cached box art image served from this site.", null=True, upload_to="games/box_art/"),
),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this game record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this game record was last updated.")),
],
options={
"ordering": ["display_name"],
},
),
migrations.CreateModel(
name="Organization",
fields=[
(
"id",
models.TextField(
help_text="The unique Twitch identifier for the organization.", primary_key=True, serialize=False, verbose_name="Organization ID"
),
),
("name", models.TextField(help_text="Display name of the organization.", unique=True, verbose_name="Name")),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this organization record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this organization record was last updated.")),
],
options={
"ordering": ["name"],
},
),
migrations.CreateModel(
@ -104,7 +98,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("entitlement_limit", models.PositiveIntegerField(default=1, help_text="Max times this benefit can be claimed for this drop.")),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this drop-benefit edge was created.")),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this drop-benefit edge was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this drop-benefit edge was last updated.")),
(
"benefit",
@ -116,7 +110,7 @@ class Migration(migrations.Migration):
name="DropCampaign",
fields=[
("id", models.TextField(help_text="Unique Twitch identifier for the campaign.", primary_key=True, serialize=False)),
("name", models.TextField(db_index=True, help_text="Name of the drop campaign.")),
("name", models.TextField(help_text="Name of the drop campaign.")),
("description", models.TextField(blank=True, help_text="Detailed description of the campaign.")),
("details_url", models.URLField(blank=True, default="", help_text="URL with campaign details.", max_length=500)),
("account_link_url", models.URLField(blank=True, default="", help_text="URL to link a Twitch account for the campaign.", max_length=500)),
@ -125,11 +119,11 @@ class Migration(migrations.Migration):
"image_file",
models.FileField(blank=True, help_text="Locally cached campaign image served from this site.", null=True, upload_to="campaigns/images/"),
),
("start_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when the campaign starts.", null=True)),
("end_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when the campaign ends.", null=True)),
("start_at", models.DateTimeField(blank=True, help_text="Datetime when the campaign starts.", null=True)),
("end_at", models.DateTimeField(blank=True, help_text="Datetime when the campaign ends.", null=True)),
("is_account_connected", models.BooleanField(default=False, help_text="Indicates if the user account is linked.")),
("allow_is_enabled", models.BooleanField(default=True, help_text="Whether the campaign allows participation.")),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this campaign record was created.")),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this campaign record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this campaign record was last updated.")),
(
"allow_channels",
@ -155,24 +149,6 @@ class Migration(migrations.Migration):
"ordering": ["-start_at"],
},
),
migrations.CreateModel(
name="Organization",
fields=[
(
"id",
models.TextField(
help_text="The unique Twitch identifier for the organization.", primary_key=True, serialize=False, verbose_name="Organization ID"
),
),
("name", models.TextField(db_index=True, help_text="Display name of the organization.", unique=True, verbose_name="Name")),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this organization record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this organization record was last updated.")),
],
options={
"ordering": ["name"],
"indexes": [models.Index(fields=["name"], name="twitch_orga_name_febe72_idx")],
},
),
migrations.AddField(
model_name="game",
name="owner",
@ -190,15 +166,15 @@ class Migration(migrations.Migration):
name="TimeBasedDrop",
fields=[
("id", models.TextField(help_text="Unique Twitch identifier for the time-based drop.", primary_key=True, serialize=False)),
("name", models.TextField(db_index=True, help_text="Name of the time-based drop.")),
("name", models.TextField(help_text="Name of the time-based drop.")),
(
"required_minutes_watched",
models.PositiveIntegerField(blank=True, db_index=True, help_text="Minutes required to watch before earning this drop.", null=True),
models.PositiveIntegerField(blank=True, help_text="Minutes required to watch before earning this drop.", null=True),
),
("required_subs", models.PositiveIntegerField(default=0, help_text="Number of subscriptions required to unlock this drop.")),
("start_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when this drop becomes available.", null=True)),
("end_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when this drop expires.", null=True)),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this time-based drop record was created.")),
("start_at", models.DateTimeField(blank=True, help_text="Datetime when this drop becomes available.", null=True)),
("end_at", models.DateTimeField(blank=True, help_text="Datetime when this drop expires.", null=True)),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Timestamp when this time-based drop record was created.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this time-based drop record was last updated.")),
(
"benefits",
@ -231,7 +207,7 @@ class Migration(migrations.Migration):
name="TwitchGameData",
fields=[
("id", models.TextField(primary_key=True, serialize=False, verbose_name="Twitch Game ID")),
("name", models.TextField(blank=True, db_index=True, default="", verbose_name="Name")),
("name", models.TextField(blank=True, default="", verbose_name="Name")),
(
"box_art_url",
models.URLField(
@ -243,7 +219,7 @@ class Migration(migrations.Migration):
),
),
("igdb_id", models.TextField(blank=True, default="", verbose_name="IGDB ID")),
("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Record creation time.")),
("added_at", models.DateTimeField(auto_now_add=True, help_text="Record creation time.")),
("updated_at", models.DateTimeField(auto_now=True, help_text="Record last update time.")),
(
"game",
@ -262,83 +238,8 @@ class Migration(migrations.Migration):
"ordering": ["name"],
},
),
migrations.AddIndex(
model_name="dropcampaign",
index=models.Index(fields=["name"], name="twitch_drop_name_3b70b3_idx"),
),
migrations.AddIndex(
model_name="dropcampaign",
index=models.Index(fields=["start_at", "end_at"], name="twitch_drop_start_a_6e5fb6_idx"),
),
migrations.AddIndex(
model_name="dropcampaign",
index=models.Index(
condition=models.Q(("end_at__isnull", False), ("start_at__isnull", False)), fields=["start_at", "end_at"], name="campaign_active_partial_idx"
),
),
migrations.AddConstraint(
model_name="dropcampaign",
constraint=models.CheckConstraint(
condition=models.Q(("start_at__isnull", True), ("end_at__isnull", True), ("end_at__gt", models.F("start_at")), _connector="OR"),
name="campaign_valid_date_range",
),
),
migrations.AddIndex(
model_name="game",
index=models.Index(fields=["display_name"], name="twitch_game_display_a35ba3_idx"),
),
migrations.AddIndex(
model_name="game",
index=models.Index(fields=["name"], name="twitch_game_name_c92c15_idx"),
),
migrations.AddIndex(
model_name="game",
index=models.Index(fields=["slug"], name="twitch_game_slug_a02d3c_idx"),
),
migrations.AddIndex(
model_name="game",
index=models.Index(condition=models.Q(("owner__isnull", False)), fields=["owner"], name="game_owner_partial_idx"),
),
migrations.AddIndex(
model_name="timebaseddrop",
index=models.Index(fields=["name"], name="twitch_time_name_47c0f4_idx"),
),
migrations.AddIndex(
model_name="timebaseddrop",
index=models.Index(fields=["start_at", "end_at"], name="twitch_time_start_a_c481f1_idx"),
),
migrations.AddIndex(
model_name="timebaseddrop",
index=models.Index(fields=["required_minutes_watched"], name="twitch_time_require_82c30c_idx"),
),
migrations.AddIndex(
model_name="timebaseddrop",
index=models.Index(fields=["campaign", "start_at", "required_minutes_watched"], name="twitch_time_campaig_4cc3b7_idx"),
),
migrations.AddConstraint(
model_name="timebaseddrop",
constraint=models.CheckConstraint(
condition=models.Q(("start_at__isnull", True), ("end_at__isnull", True), ("end_at__gt", models.F("start_at")), _connector="OR"),
name="drop_valid_date_range",
),
),
migrations.AddConstraint(
model_name="timebaseddrop",
constraint=models.CheckConstraint(
condition=models.Q(("required_minutes_watched__isnull", True), ("required_minutes_watched__gte", 0), _connector="OR"),
name="drop_positive_minutes",
),
),
migrations.AddIndex(
model_name="dropbenefitedge",
index=models.Index(fields=["drop", "benefit"], name="twitch_drop_drop_id_5a574c_idx"),
),
migrations.AddConstraint(
model_name="dropbenefitedge",
constraint=models.UniqueConstraint(fields=("drop", "benefit"), name="unique_drop_benefit"),
),
migrations.AddIndex(
model_name="twitchgamedata",
index=models.Index(fields=["name"], name="twitch_twit_name_5dda5f_idx"),
),
]

View file

@ -1,7 +1,7 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, ClassVar
from typing import TYPE_CHECKING
from django.db import models
from django.utils import timezone
@ -22,7 +22,6 @@ class Organization(models.Model):
help_text="The unique Twitch identifier for the organization.",
)
name = models.TextField(
db_index=True,
unique=True,
verbose_name="Name",
help_text="Display name of the organization.",
@ -30,7 +29,6 @@ class Organization(models.Model):
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this organization record was created.",
)
updated_at = models.DateTimeField(
@ -40,9 +38,6 @@ class Organization(models.Model):
class Meta:
ordering = ["name"]
indexes: ClassVar[list] = [
models.Index(fields=["name"]),
]
def __str__(self) -> str:
"""Return a string representation of the organization."""
@ -58,20 +53,17 @@ class Game(models.Model):
max_length=200,
blank=True,
default="",
db_index=True,
verbose_name="Slug",
help_text="Short unique identifier for the game.",
)
name = models.TextField(
blank=True,
default="",
db_index=True,
verbose_name="Name",
)
display_name = models.TextField(
blank=True,
default="",
db_index=True,
verbose_name="Display name",
)
box_art = models.URLField(
@ -100,7 +92,6 @@ class Game(models.Model):
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this game record was created.",
)
updated_at = models.DateTimeField(
@ -110,12 +101,6 @@ class Game(models.Model):
class Meta:
ordering = ["display_name"]
indexes: ClassVar[list] = [
models.Index(fields=["display_name"]),
models.Index(fields=["name"]),
models.Index(fields=["slug"]),
models.Index(fields=["owner"], condition=models.Q(owner__isnull=False), name="game_owner_partial_idx"),
]
def __str__(self) -> str:
"""Return a string representation of the game."""
@ -177,7 +162,7 @@ class TwitchGameData(models.Model):
help_text="Optional link to the local Game record for this Twitch game.",
)
name = models.TextField(blank=True, default="", db_index=True, verbose_name="Name")
name = models.TextField(blank=True, default="", verbose_name="Name")
box_art_url = models.URLField(
max_length=500,
blank=True,
@ -187,14 +172,11 @@ class TwitchGameData(models.Model):
)
igdb_id = models.TextField(blank=True, default="", verbose_name="IGDB ID")
added_at = models.DateTimeField(auto_now_add=True, db_index=True, help_text="Record creation time.")
added_at = models.DateTimeField(auto_now_add=True, help_text="Record creation time.")
updated_at = models.DateTimeField(auto_now=True, help_text="Record last update time.")
class Meta:
ordering = ["name"]
indexes: ClassVar[list] = [
models.Index(fields=["name"]),
]
def __str__(self) -> str:
return self.name or self.id
@ -210,19 +192,16 @@ class Channel(models.Model):
help_text="The unique Twitch identifier for the channel.",
)
name = models.TextField(
db_index=True,
verbose_name="Username",
help_text="The lowercase username of the channel.",
)
display_name = models.TextField(
db_index=True,
verbose_name="Display Name",
help_text="The display name of the channel (with proper capitalization).",
)
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this channel record was created.",
)
updated_at = models.DateTimeField(
@ -232,10 +211,6 @@ class Channel(models.Model):
class Meta:
ordering = ["display_name"]
indexes: ClassVar[list] = [
models.Index(fields=["name"]),
models.Index(fields=["display_name"]),
]
def __str__(self) -> str:
"""Return a string representation of the channel."""
@ -251,7 +226,6 @@ class DropCampaign(models.Model):
help_text="Unique Twitch identifier for the campaign.",
)
name = models.TextField(
db_index=True,
help_text="Name of the drop campaign.",
)
description = models.TextField(
@ -283,13 +257,11 @@ class DropCampaign(models.Model):
help_text="Locally cached campaign image served from this site.",
)
start_at = models.DateTimeField(
db_index=True,
null=True,
blank=True,
help_text="Datetime when the campaign starts.",
)
end_at = models.DateTimeField(
db_index=True,
null=True,
blank=True,
help_text="Datetime when the campaign ends.",
@ -319,7 +291,6 @@ class DropCampaign(models.Model):
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this campaign record was created.",
)
updated_at = models.DateTimeField(
@ -330,12 +301,6 @@ class DropCampaign(models.Model):
class Meta:
ordering = ["-start_at"]
indexes: ClassVar[list] = [
models.Index(fields=["name"]),
models.Index(fields=["start_at", "end_at"]),
models.Index(fields=["start_at", "end_at"], condition=models.Q(start_at__isnull=False, end_at__isnull=False), name="campaign_active_partial_idx"),
]
def __str__(self) -> str:
return self.name
@ -396,7 +361,6 @@ class DropBenefit(models.Model):
help_text="Unique Twitch identifier for the benefit.",
)
name = models.TextField(
db_index=True,
blank=True,
default="N/A",
help_text="Name of the drop benefit.",
@ -415,7 +379,6 @@ class DropBenefit(models.Model):
)
created_at = models.DateTimeField(
null=True,
db_index=True,
help_text="Timestamp when the benefit was created. This is from Twitch API and not auto-generated.",
)
entitlement_limit = models.PositiveIntegerField(
@ -430,7 +393,6 @@ class DropBenefit(models.Model):
)
distribution_type = models.TextField(
max_length=50,
db_index=True,
blank=True,
default="",
help_text="Type of distribution for this benefit.",
@ -438,7 +400,6 @@ class DropBenefit(models.Model):
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this benefit record was created.",
)
updated_at = models.DateTimeField(
@ -448,12 +409,6 @@ class DropBenefit(models.Model):
class Meta:
ordering = ["-created_at"]
indexes: ClassVar[list] = [
models.Index(fields=["name"]),
models.Index(fields=["created_at"]),
models.Index(fields=["distribution_type"]),
models.Index(fields=["is_ios_available"], condition=models.Q(is_ios_available=True), name="benefit_ios_available_idx"),
]
def __str__(self) -> str:
"""Return a string representation of the drop benefit."""
@ -469,11 +424,9 @@ class TimeBasedDrop(models.Model):
help_text="Unique Twitch identifier for the time-based drop.",
)
name = models.TextField(
db_index=True,
help_text="Name of the time-based drop.",
)
required_minutes_watched = models.PositiveIntegerField(
db_index=True,
null=True,
blank=True,
help_text="Minutes required to watch before earning this drop.",
@ -483,13 +436,11 @@ class TimeBasedDrop(models.Model):
help_text="Number of subscriptions required to unlock this drop.",
)
start_at = models.DateTimeField(
db_index=True,
null=True,
blank=True,
help_text="Datetime when this drop becomes available.",
)
end_at = models.DateTimeField(
db_index=True,
null=True,
blank=True,
help_text="Datetime when this drop expires.",
@ -511,7 +462,6 @@ class TimeBasedDrop(models.Model):
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this time-based drop record was created.",
)
updated_at = models.DateTimeField(
@ -521,12 +471,6 @@ class TimeBasedDrop(models.Model):
class Meta:
ordering = ["start_at"]
indexes: ClassVar[list] = [
models.Index(fields=["name"]),
models.Index(fields=["start_at", "end_at"]),
models.Index(fields=["required_minutes_watched"]),
models.Index(fields=["campaign", "start_at", "required_minutes_watched"]),
]
def __str__(self) -> str:
"""Return a string representation of the time-based drop."""
@ -554,7 +498,6 @@ class DropBenefitEdge(models.Model):
added_at = models.DateTimeField(
auto_now_add=True,
db_index=True,
help_text="Timestamp when this drop-benefit edge was created.",
)
updated_at = models.DateTimeField(
@ -566,9 +509,6 @@ class DropBenefitEdge(models.Model):
constraints = [
models.UniqueConstraint(fields=("drop", "benefit"), name="unique_drop_benefit"),
]
indexes: ClassVar[list] = [
models.Index(fields=["drop", "benefit"]),
]
def __str__(self) -> str:
"""Return a string representation of the drop benefit edge."""