summaryrefslogtreecommitdiff
path: root/kitchen
diff options
context:
space:
mode:
authorCaine <caine@jihakuz.xyz>2026-04-01 22:50:04 +0100
committerCaine <caine@jihakuz.xyz>2026-04-01 22:50:04 +0100
commite76a8fe656ba12aadfc0abe8d5c2d81b1051866f (patch)
tree7408b886127a61d66122a20eb38e886fcb9aa4fa /kitchen
parent999ca28b67c46f9f11f9ec1ebc0c91cb2fa82287 (diff)
Add seed command: 29 ingredients, pantry from Pantry.md, 2 meta-recipes (stir fry + traybake)
Diffstat (limited to 'kitchen')
-rw-r--r--kitchen/management/__init__.py1
-rw-r--r--kitchen/management/commands/__init__.py1
-rw-r--r--kitchen/management/commands/seed.py245
3 files changed, 247 insertions, 0 deletions
diff --git a/kitchen/management/__init__.py b/kitchen/management/__init__.py
new file mode 100644
index 0000000..7fdf6c6
--- /dev/null
+++ b/kitchen/management/__init__.py
@@ -0,0 +1 @@
+# management package
diff --git a/kitchen/management/commands/__init__.py b/kitchen/management/commands/__init__.py
new file mode 100644
index 0000000..354dfbb
--- /dev/null
+++ b/kitchen/management/commands/__init__.py
@@ -0,0 +1 @@
+# commands package
diff --git a/kitchen/management/commands/seed.py b/kitchen/management/commands/seed.py
new file mode 100644
index 0000000..4aa74bf
--- /dev/null
+++ b/kitchen/management/commands/seed.py
@@ -0,0 +1,245 @@
+"""
+Seed the database with initial data:
+- Tags
+- Ingredients (from current pantry + recipe knowledge)
+- Current pantry items (migrated from Food/Pantry.md)
+- Meta-recipes: Stir Fry and Traybake
+"""
+
+from datetime import date
+from decimal import Decimal
+
+from django.core.management.base import BaseCommand
+
+from kitchen.models import (
+ Tag,
+ Ingredient,
+ PantryItem,
+ MetaRecipe,
+ Slot,
+ SlotOption,
+ MetaRecipeBase,
+)
+
+
+class Command(BaseCommand):
+ help = "Seed database with initial ingredients, pantry, and meta-recipes"
+
+ def handle(self, *args, **options):
+ self.stdout.write("Creating tags...")
+ tags = {}
+ for name in ["protein", "carb", "veg", "seasoning", "dairy", "sauce", "staple", "frozen"]:
+ tags[name], _ = Tag.objects.get_or_create(name=name)
+
+ self.stdout.write("Creating ingredients...")
+ ingredients = {}
+
+ def make_ingredient(name, unit, tag_names, shelf_life=None, aliases=None):
+ obj, _ = Ingredient.objects.get_or_create(
+ name=name,
+ defaults={
+ "default_unit": unit,
+ "shelf_life_days": shelf_life,
+ "aliases": aliases or [],
+ },
+ )
+ for t in tag_names:
+ obj.tags.add(tags[t])
+ ingredients[name] = obj
+ return obj
+
+ # Proteins
+ make_ingredient("chicken mini fillets", "items", ["protein"], shelf_life=2, aliases=["chicken fillets", "mini fillets"])
+ make_ingredient("chicken thighs", "items", ["protein"], shelf_life=2, aliases=["chicken thigh"])
+ make_ingredient("pork mince", "g", ["protein"], shelf_life=2, aliases=["pork mince 500g"])
+ make_ingredient("sausages", "items", ["protein"], shelf_life=5, aliases=["pork sausages"])
+
+ # Carbs
+ make_ingredient("egg noodles", "nests", ["carb"], aliases=["noodles", "egg noodle nests"])
+ make_ingredient("microwave rice", "packets", ["carb"], aliases=["rice"])
+ make_ingredient("pasta", "g", ["carb"], aliases=["dried pasta"])
+ make_ingredient("bread", "loaves", ["carb"], shelf_life=5)
+ make_ingredient("frozen chips", "bags", ["carb", "frozen", "staple"], aliases=["chips", "McCain chips"])
+
+ # Veg
+ make_ingredient("onions", "items", ["veg", "staple"], aliases=["onion"])
+ make_ingredient("garlic", "bulbs", ["veg"], shelf_life=14, aliases=["garlic bulb"])
+ make_ingredient("frozen stir fry veg", "bags", ["veg", "frozen"], aliases=["stir fry veg", "Birds Eye stir fry veg"])
+ make_ingredient("broccoli", "heads", ["veg"], shelf_life=5)
+ make_ingredient("peppers", "items", ["veg"], shelf_life=7, aliases=["pepper", "bell pepper"])
+ make_ingredient("potatoes", "items", ["veg"], shelf_life=14, aliases=["Cyprus potatoes"])
+ make_ingredient("chopped tomatoes", "tins", ["veg"], aliases=["tinned tomatoes"])
+
+ # Dairy / Other
+ make_ingredient("eggs", "items", ["protein"], shelf_life=14, aliases=["free range eggs"])
+ make_ingredient("milk", "bottles", ["dairy"], shelf_life=7)
+ make_ingredient("Lurpak spreadable", "tubs", ["dairy"], aliases=["butter", "Lurpak"])
+
+ # Seasonings & Sauces
+ make_ingredient("salt", "n/a", ["seasoning", "staple"])
+ make_ingredient("black pepper", "n/a", ["seasoning", "staple"])
+ make_ingredient("olive oil", "bottles", ["seasoning", "staple"])
+ make_ingredient("paprika", "n/a", ["seasoning", "staple"])
+ make_ingredient("garlic powder", "n/a", ["seasoning", "staple"])
+ make_ingredient("soy sauce", "bottles", ["sauce"], aliases=["soy"])
+ make_ingredient("Lao Gan Ma", "jars", ["sauce"], aliases=["chilli crisp"])
+ make_ingredient("peanut butter", "jars", ["staple"], aliases=["Whole Earth crunchy"])
+
+ # Other
+ make_ingredient("baked beans", "tins", ["staple"])
+ make_ingredient("freezer bags", "boxes", ["staple"], aliases=["Tesco tie handle"])
+
+ self.stdout.write(f" Created {len(ingredients)} ingredients")
+
+ # --- Pantry Items (from current Pantry.md as of 31 Mar 2026) ---
+ self.stdout.write("Creating pantry items...")
+
+ def add_pantry(name, qty, unit, location, expiry=None, is_staple=False, notes=""):
+ PantryItem.objects.get_or_create(
+ ingredient=ingredients[name],
+ defaults={
+ "quantity": Decimal(str(qty)),
+ "unit": unit,
+ "location": location,
+ "expiry_date": expiry,
+ "is_staple": is_staple,
+ "notes": notes,
+ },
+ )
+
+ # Fridge
+ add_pantry("onions", 2, "items", "fridge", is_staple=True)
+ add_pantry("milk", 1, "bottles", "fridge", expiry=date(2026, 4, 3))
+ add_pantry("egg noodles", 1, "nests", "fridge")
+ add_pantry("garlic", 1, "bulbs", "fridge", expiry=date(2026, 4, 2), notes="minus 2 cloves")
+ add_pantry("bread", 1, "loaves", "fridge", expiry=date(2026, 4, 1))
+ add_pantry("pasta", 4, "portions", "cupboard")
+ add_pantry("microwave rice", 2, "packets", "cupboard")
+ add_pantry("peanut butter", 1, "jars", "cupboard")
+ add_pantry("Lurpak spreadable", 1, "tubs", "fridge")
+ add_pantry("Lao Gan Ma", 1, "jars", "cupboard")
+ add_pantry("sausages", 3, "items", "fridge", expiry=date(2026, 3, 30), notes="Likely expired — sniff test")
+
+ # Freezer
+ add_pantry("sausages", 3, "items", "freezer", notes="From frozen pack")
+ add_pantry("frozen chips", 1, "bags", "freezer", is_staple=True)
+ add_pantry("bread", 1, "loaves", "freezer", notes="Sliced")
+
+ # Staples (seasonings — always in cupboard)
+ for name in ["salt", "black pepper", "olive oil", "paprika", "garlic powder"]:
+ add_pantry(name, 1, "n/a", "cupboard", is_staple=True)
+
+ # Out of stock (for reference)
+ add_pantry("eggs", 0, "items", "fridge", notes="OUT — restock")
+ add_pantry("baked beans", 1, "tins", "cupboard")
+ add_pantry("freezer bags", 1, "boxes", "cupboard")
+
+ self.stdout.write(" Pantry seeded")
+
+ # --- Meta-Recipes ---
+ self.stdout.write("Creating meta-recipes...")
+
+ # === STIR FRY ===
+ stir_fry, _ = MetaRecipe.objects.get_or_create(
+ name="Stir Fry",
+ defaults={
+ "method": (
+ "1. Defrost protein if frozen (cold water, ~30 mins for fillets)\n"
+ "2. Slice protein thin, fry in oil til cooked through\n"
+ "3. Dice onion + mince garlic, add to pan\n"
+ "4. Add veg (frozen goes straight in)\n"
+ "5. Boil carb separately if needed (noodles 4 mins, rice per packet)\n"
+ "6. Toss everything together with sauce\n"
+ "7. Optional: push to one side, crack egg in, scramble, mix through"
+ ),
+ "prep_time_mins": 10,
+ "cook_time_mins": 15,
+ "default_servings": 2,
+ "gear_needed": "frying pan, saucepan",
+ "tags": ["quick", "one-pan"],
+ },
+ )
+
+ # Stir fry slots
+ sf_protein, _ = Slot.objects.get_or_create(
+ meta_recipe=stir_fry, name="protein", defaults={"required": True, "max_choices": 1}
+ )
+ sf_carb, _ = Slot.objects.get_or_create(
+ meta_recipe=stir_fry, name="carb", defaults={"required": True, "max_choices": 1}
+ )
+ sf_veg, _ = Slot.objects.get_or_create(
+ meta_recipe=stir_fry, name="veg", defaults={"required": True, "max_choices": 3}
+ )
+ sf_sauce, _ = Slot.objects.get_or_create(
+ meta_recipe=stir_fry, name="sauce", defaults={"required": False, "max_choices": 2}
+ )
+
+ # Stir fry slot options
+ SlotOption.objects.get_or_create(slot=sf_protein, ingredient=ingredients["chicken mini fillets"], defaults={"quantity_per_serving": Decimal("2"), "unit": "items", "notes": "defrost first"})
+ SlotOption.objects.get_or_create(slot=sf_protein, ingredient=ingredients["pork mince"], defaults={"quantity_per_serving": Decimal("250"), "unit": "g"})
+ SlotOption.objects.get_or_create(slot=sf_carb, ingredient=ingredients["egg noodles"], defaults={"quantity_per_serving": Decimal("2"), "unit": "nests"})
+ SlotOption.objects.get_or_create(slot=sf_carb, ingredient=ingredients["microwave rice"], defaults={"quantity_per_serving": Decimal("1"), "unit": "packets"})
+ SlotOption.objects.get_or_create(slot=sf_veg, ingredient=ingredients["frozen stir fry veg"], defaults={"quantity_per_serving": Decimal("0.5"), "unit": "bags"})
+ SlotOption.objects.get_or_create(slot=sf_veg, ingredient=ingredients["broccoli"], defaults={"quantity_per_serving": Decimal("0.5"), "unit": "heads"})
+ SlotOption.objects.get_or_create(slot=sf_veg, ingredient=ingredients["peppers"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
+ SlotOption.objects.get_or_create(slot=sf_sauce, ingredient=ingredients["soy sauce"], defaults={"quantity_per_serving": Decimal("1"), "unit": "splash"})
+ SlotOption.objects.get_or_create(slot=sf_sauce, ingredient=ingredients["Lao Gan Ma"], defaults={"quantity_per_serving": Decimal("1"), "unit": "spoonful"})
+
+ # Stir fry base ingredients
+ MetaRecipeBase.objects.get_or_create(meta_recipe=stir_fry, ingredient=ingredients["onions"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
+ MetaRecipeBase.objects.get_or_create(meta_recipe=stir_fry, ingredient=ingredients["garlic"], defaults={"quantity_per_serving": Decimal("2"), "unit": "cloves"})
+ MetaRecipeBase.objects.get_or_create(meta_recipe=stir_fry, ingredient=ingredients["olive oil"], defaults={"quantity_per_serving": Decimal("1"), "unit": "splash"})
+
+ # === TRAYBAKE ===
+ traybake, _ = MetaRecipe.objects.get_or_create(
+ name="Traybake",
+ defaults={
+ "method": (
+ "1. Preheat oven to 200°C\n"
+ "2. Dice onion, chop veg into chunks\n"
+ "3. Toss protein + veg in oil and seasoning on baking tray\n"
+ "4. Spread out in single layer\n"
+ "5. Oven for 30-40 mins, turning halfway\n"
+ "6. If using chicken thighs: remove skin before cooking"
+ ),
+ "prep_time_mins": 10,
+ "cook_time_mins": 35,
+ "default_servings": 2,
+ "gear_needed": "baking tray",
+ "tags": ["easy", "one-tray", "batch-cook"],
+ },
+ )
+
+ # Traybake slots
+ tb_protein, _ = Slot.objects.get_or_create(
+ meta_recipe=traybake, name="protein", defaults={"required": True, "max_choices": 1}
+ )
+ tb_veg, _ = Slot.objects.get_or_create(
+ meta_recipe=traybake, name="veg", defaults={"required": True, "max_choices": 3}
+ )
+ tb_seasoning, _ = Slot.objects.get_or_create(
+ meta_recipe=traybake, name="seasoning", defaults={"required": True, "max_choices": 1}
+ )
+
+ # Traybake slot options
+ SlotOption.objects.get_or_create(slot=tb_protein, ingredient=ingredients["sausages"], defaults={"quantity_per_serving": Decimal("3"), "unit": "items"})
+ SlotOption.objects.get_or_create(slot=tb_protein, ingredient=ingredients["chicken thighs"], defaults={"quantity_per_serving": Decimal("2"), "unit": "items", "notes": "skin off"})
+ SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["peppers"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
+ SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["broccoli"], defaults={"quantity_per_serving": Decimal("0.5"), "unit": "heads"})
+ SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["potatoes"], defaults={"quantity_per_serving": Decimal("2"), "unit": "items"})
+ SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["frozen chips"], defaults={"quantity_per_serving": Decimal("1"), "unit": "handful"})
+ SlotOption.objects.get_or_create(slot=tb_seasoning, ingredient=ingredients["paprika"], defaults={"quantity_per_serving": Decimal("1"), "unit": "tsp"})
+
+ # Traybake base ingredients
+ MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["onions"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
+ MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["olive oil"], defaults={"quantity_per_serving": Decimal("1"), "unit": "drizzle"})
+ MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["salt"], defaults={"quantity_per_serving": Decimal("1"), "unit": "pinch"})
+ MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["black pepper"], defaults={"quantity_per_serving": Decimal("1"), "unit": "pinch"})
+
+ self.stdout.write(self.style.SUCCESS("✅ Seed complete!"))
+ self.stdout.write(f" Tags: {Tag.objects.count()}")
+ self.stdout.write(f" Ingredients: {Ingredient.objects.count()}")
+ self.stdout.write(f" Pantry items: {PantryItem.objects.count()}")
+ self.stdout.write(f" Meta-recipes: {MetaRecipe.objects.count()}")
+ self.stdout.write(f" Slots: {Slot.objects.count()}")
+ self.stdout.write(f" Slot options: {SlotOption.objects.count()}")