Anchor DLC purchases to a base game instead of a parent purchase
Django CI/CD / test (push) Successful in 3m35s
Staging deployment / deploy (push) Successful in 1m24s
Staging deployment / comment (push) Has been skipped
Staging deployment / teardown (push) Has been skipped
Django CI/CD / build-and-push (push) Has been skipped
Django CI/CD / test (push) Successful in 3m35s
Staging deployment / deploy (push) Successful in 1m24s
Staging deployment / comment (push) Has been skipped
Staging deployment / teardown (push) Has been skipped
Django CI/CD / build-and-push (push) Has been skipped
Add-on purchases (DLC, Season Pass, Battle Pass) previously linked to a parent *purchase* via the `related_purchase` self-FK. When the base game was bought inside a multi-game purchase (e.g. a bundle), there was no per-game purchase to point at — only the whole bundle. Replace it with a `related_game` FK (Game -> Game): an add-on belongs to a *game*, which is unambiguous regardless of how the base game was bought. - models: drop `related_purchase`; add `related_game` (SET_NULL, related_name="addon_purchases"); require it for non-GAME types in `save()`. - forms: replace the parent-purchase picker with a flat `related_game` game search (reusing SearchSelectWidget/_game_options); drop the now unused related_purchase_queryset/RelatedPurchaseChoiceField. - views/urls: remove the obsolete related_purchase_by_game endpoint. - add_purchase.js: drop the parent-dropdown refetch; keep platform auto-fill; retarget the type toggle to #id_related_game. - migration 0020: add -> backfill (related_game = parent's first game by sort_name) -> remove related_purchase. - tests: model validation unit tests + an e2e test for the flat picker. related_game is deliberately game->game so it can later be synced from IGDB's parent_game without schema changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-18 21:03
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def backfill_related_game(apps, schema_editor):
|
||||
"""Move each add-on purchase's parent link from the parent *purchase* to a
|
||||
parent *game*. For a parent bought as a multi-game bundle there is no single
|
||||
game, so use the bundle's first game (by sort_name) as the best guess."""
|
||||
Purchase = apps.get_model("games", "Purchase")
|
||||
for purchase in Purchase.objects.filter(related_purchase__isnull=False):
|
||||
parent_game = purchase.related_purchase.games.order_by("sort_name").first()
|
||||
if parent_game is not None:
|
||||
purchase.related_game = parent_game
|
||||
purchase.save(update_fields=["related_game"])
|
||||
|
||||
|
||||
def noop_reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("games", "0019_alter_filterpreset_mode"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="purchase",
|
||||
name="related_game",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="addon_purchases",
|
||||
to="games.game",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(backfill_related_game, noop_reverse),
|
||||
migrations.RemoveField(
|
||||
model_name="purchase",
|
||||
name="related_purchase",
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user