Create basic recipe stuff.
This commit is contained in:
parent
d31d53ca9b
commit
e0ac1f96db
@ -3,8 +3,8 @@ from django.urls import reverse
|
|||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
|
||||||
from beer.models import Batch, BatchRecipe, BatchRecipe
|
from beer.models import Batch, BatchRecipe, Mash, MashStep, RecipeFermentable, RecipeHop, RecipeMisc, RecipeYeast
|
||||||
from yeast.models import Yeast
|
from yeast.models import Yeast, Strain
|
||||||
|
|
||||||
from config.extras import BREWFATHER_APP_ROOT
|
from config.extras import BREWFATHER_APP_ROOT
|
||||||
|
|
||||||
@ -12,9 +12,31 @@ class SampleInline(admin.TabularInline):
|
|||||||
model = Yeast
|
model = Yeast
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
class FermentableInline(admin.TabularInline):
|
||||||
|
model = RecipeFermentable
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
class HopInline(admin.TabularInline):
|
||||||
|
model = RecipeHop
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
class MiscInline(admin.TabularInline):
|
||||||
|
model = RecipeMisc
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
class StrainInline(admin.TabularInline):
|
||||||
|
model = RecipeYeast
|
||||||
|
extra = 1
|
||||||
|
|
||||||
@admin.register(BatchRecipe)
|
@admin.register(BatchRecipe)
|
||||||
class BatchRecipeAdmin(admin.ModelAdmin):
|
class BatchRecipeAdmin(admin.ModelAdmin):
|
||||||
list_display = ['name']
|
list_display = ['name']
|
||||||
|
inlines = [
|
||||||
|
FermentableInline,
|
||||||
|
HopInline,
|
||||||
|
MiscInline,
|
||||||
|
StrainInline
|
||||||
|
]
|
||||||
|
|
||||||
@admin.register(Batch)
|
@admin.register(Batch)
|
||||||
class BeerBatchAdmin(admin.ModelAdmin):
|
class BeerBatchAdmin(admin.ModelAdmin):
|
||||||
@ -30,6 +52,17 @@ class BeerBatchAdmin(admin.ModelAdmin):
|
|||||||
return format_html("<a href='{root}/tabs/batches/batch/{batch_id}'>Brewfather App: {batch_id}</a>", batch_id=bf_id, root=BREWFATHER_APP_ROOT)
|
return format_html("<a href='{root}/tabs/batches/batch/{batch_id}'>Brewfather App: {batch_id}</a>", batch_id=bf_id, root=BREWFATHER_APP_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
class MashStepInline(admin.TabularInline):
|
||||||
|
model = MashStep
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
@admin.register(Mash)
|
||||||
|
class MashAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['name', ]
|
||||||
|
inlines = [
|
||||||
|
MashStepInline,
|
||||||
|
]
|
||||||
|
|
||||||
app = apps.get_app_config('beer')
|
app = apps.get_app_config('beer')
|
||||||
for model_name, model in app.models.items():
|
for model_name, model in app.models.items():
|
||||||
|
|
||||||
|
@ -9,6 +9,42 @@ RECIPE_URL = 'https://api.brewfather.app/v2/recipes'
|
|||||||
BATCH_URL = 'https://api.brewfather.app/v2/batches'
|
BATCH_URL = 'https://api.brewfather.app/v2/batches'
|
||||||
PULL_LIMIT = 50
|
PULL_LIMIT = 50
|
||||||
|
|
||||||
|
BREWFATHER_CONVERT_LOOKUP = { # local_name: brewfather_name
|
||||||
|
'all': {
|
||||||
|
'name': 'name',
|
||||||
|
'unit_cost': 'costPerAmount',
|
||||||
|
'supplier': 'supplier',
|
||||||
|
'notes': 'notes',
|
||||||
|
'user_notes': 'userNotes',
|
||||||
|
},
|
||||||
|
'fermentable': {
|
||||||
|
'grain_category': 'grainCategory',
|
||||||
|
'fermentable_type': 'type',
|
||||||
|
'diastatic_power': 'diastaticPower',
|
||||||
|
'potential': 'potential',
|
||||||
|
'protein': 'protein',
|
||||||
|
'attenuation': 'attenuation',
|
||||||
|
'lovibond': 'lovibond',
|
||||||
|
'max_in_batch': 'maxInBatch',
|
||||||
|
'moisture': 'moisture',
|
||||||
|
'non_fermentable': 'notFermentable',
|
||||||
|
'ibu_per_unit': 'ibuPerAmount',
|
||||||
|
},
|
||||||
|
'hop': {
|
||||||
|
'ibu': 'ibu',
|
||||||
|
'use': 'use',
|
||||||
|
'hop_type': 'type',
|
||||||
|
'alpha': 'alpha',
|
||||||
|
|
||||||
|
},
|
||||||
|
'misc': {
|
||||||
|
'use': 'use',
|
||||||
|
'misc_type': 'type',
|
||||||
|
'water_adjustment': 'waterAdjustment',
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def get_batches(api_user, api_key, batch=''):
|
def get_batches(api_user, api_key, batch=''):
|
||||||
auth_string = api_user + ':' + api_key
|
auth_string = api_user + ':' + api_key
|
||||||
|
|
||||||
|
@ -0,0 +1,217 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-06-17 17:13
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('beer', '0003_delete_recipe_batchrecipe_batch_recipe_and_more'),
|
||||||
|
('yeast', '0004_alter_propogation_options'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Fermentable',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('unit_cost', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
|
||||||
|
('notes', models.TextField(blank=True, max_length=500, null=True)),
|
||||||
|
('user_notes', models.TextField(blank=True, max_length=500, null=True)),
|
||||||
|
('grain_category', models.IntegerField(choices=[(1, 'Base'), (2, 'Wheat/Oat'), (3, 'Crystal'), (4, 'Roasted'), (5, 'Acid')], default=1)),
|
||||||
|
('fermentable_type', models.IntegerField(choices=[(1, 'Grain'), (2, 'Adjunct')], default=1)),
|
||||||
|
('diastatic_power', models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True)),
|
||||||
|
('potential', models.DecimalField(decimal_places=4, max_digits=6)),
|
||||||
|
('protein', models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True)),
|
||||||
|
('attenuation', models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True)),
|
||||||
|
('lovibond', models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True)),
|
||||||
|
('max_in_batch', models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True)),
|
||||||
|
('moisture', models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True)),
|
||||||
|
('non_fermentable', models.BooleanField(blank=True, null=True)),
|
||||||
|
('ibu_per_unit', models.DecimalField(decimal_places=4, default=0, max_digits=6)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Hop',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('unit_cost', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
|
||||||
|
('notes', models.TextField(blank=True, max_length=500, null=True)),
|
||||||
|
('user_notes', models.TextField(blank=True, max_length=500, null=True)),
|
||||||
|
('ibu', models.DecimalField(decimal_places=4, default=0, max_digits=6)),
|
||||||
|
('use', models.IntegerField(choices=[(1, 'Bittering'), (2, 'Aroma'), (3, 'Both')], default=1)),
|
||||||
|
('hop_type', models.IntegerField(choices=[(1, 'Pellet'), (2, 'Leaf'), (3, 'Cryo'), (4, 'CO2 Extract')], default=1)),
|
||||||
|
('alpha', models.DecimalField(decimal_places=2, default=0, max_digits=6)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Mash',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Misc',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('unit_cost', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
|
||||||
|
('notes', models.TextField(blank=True, max_length=500, null=True)),
|
||||||
|
('user_notes', models.TextField(blank=True, max_length=500, null=True)),
|
||||||
|
('use', models.IntegerField(choices=[(1, 'Mash'), (2, 'Sparge'), (3, 'Boil'), (4, 'Flamout'), (5, 'Primary'), (6, 'Secondary'), (7, 'Cold Crash'), (8, 'Bottling')], default=1)),
|
||||||
|
('misc_type', models.IntegerField(choices=[(1, 'Spice'), (2, 'Fining'), (3, 'Water Agent'), (4, 'Herb'), (5, 'Flavor'), (6, 'Other')], default=1)),
|
||||||
|
('water_adjustment', models.BooleanField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Supplier',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Unit',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('unit_type', models.CharField(choices=[('WT', 'Weight'), ('VL', 'Volume')], default='WT', max_length=3)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='batchrecipe',
|
||||||
|
name='efficiency',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=4, max_digits=6, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='batchrecipe',
|
||||||
|
name='mash',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='beer.mash'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='MashStep',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('step_temp', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('ramp_time', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('step_time', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('step_type', models.IntegerField(choices=[(1, 'infusion'), (2, 'temperature'), (3, 'decoction')], default=1)),
|
||||||
|
('parent_mash', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.mash')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RecipeFermentable',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('quantity', models.DecimalField(decimal_places=4, max_digits=6)),
|
||||||
|
('fermentable', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.fermentable')),
|
||||||
|
('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.batchrecipe')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RecipeHop',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('quantity', models.DecimalField(decimal_places=4, max_digits=6)),
|
||||||
|
('hop', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.hop')),
|
||||||
|
('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.batchrecipe')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RecipeMisc',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('quantity', models.DecimalField(decimal_places=4, max_digits=6)),
|
||||||
|
('misc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.misc')),
|
||||||
|
('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.batchrecipe')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RecipeYeast',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beer.batchrecipe')),
|
||||||
|
('yeast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yeast.strain')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='misc',
|
||||||
|
name='supplier',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='beer.supplier'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='hop',
|
||||||
|
name='supplier',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='beer.supplier'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='fermentable',
|
||||||
|
name='supplier',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='beer.supplier'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='misc',
|
||||||
|
name='units',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='beer.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='hop',
|
||||||
|
name='units',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='beer.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='fermentable',
|
||||||
|
name='units',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='beer.unit'),
|
||||||
|
),
|
||||||
|
]
|
153
beer/models.py
153
beer/models.py
@ -37,9 +37,162 @@ class Batch(CustomModel):
|
|||||||
# Return a string that represents the instance
|
# Return a string that represents the instance
|
||||||
return 'BF #{num}: {name}'.format(name=self.brewfather_name, num=self.brewfather_num)
|
return 'BF #{num}: {name}'.format(name=self.brewfather_name, num=self.brewfather_num)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Recipe Stuff
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
class Unit(CustomModel):
|
||||||
|
unit_types = {
|
||||||
|
'WT': 'Weight',
|
||||||
|
'VL': 'Volume',
|
||||||
|
}
|
||||||
|
|
||||||
|
""" Recipe to be stored with a batch."""
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
unit_type = models.CharField(max_length=3, choices=unit_types, default='WT')
|
||||||
|
|
||||||
|
class Supplier(CustomModel):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
class CustomIngredient(CustomModel):
|
||||||
|
""" Custom model class with default fields to use. """
|
||||||
|
created_date = models.DateTimeField(default=timezone.now)
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
units = models.ForeignKey(Unit, on_delete=models.PROTECT)
|
||||||
|
unit_cost = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
|
||||||
|
supplier = models.ForeignKey(Supplier, on_delete=models.PROTECT, null=True, blank=True)
|
||||||
|
notes = models.TextField(max_length=500, blank=True, null=True)
|
||||||
|
user_notes = models.TextField(max_length=500, blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
class BatchRecipe(CustomModel):
|
class BatchRecipe(CustomModel):
|
||||||
""" Recipe to be stored with a batch."""
|
""" Recipe to be stored with a batch."""
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
batch_recipe = models.BooleanField(null=True)
|
batch_recipe = models.BooleanField(null=True)
|
||||||
recipe_json = models.TextField(null=True, blank=True)
|
recipe_json = models.TextField(null=True, blank=True)
|
||||||
|
mash = models.ForeignKey('Mash' , on_delete=models.PROTECT, null=True, blank=True)
|
||||||
|
efficiency = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Fermentable(CustomIngredient):
|
||||||
|
categories = {
|
||||||
|
1: 'Base',
|
||||||
|
2: 'Wheat/Oat',
|
||||||
|
3: 'Crystal',
|
||||||
|
4: 'Roasted',
|
||||||
|
5: 'Acid',
|
||||||
|
}
|
||||||
|
|
||||||
|
types = {
|
||||||
|
1: 'Grain',
|
||||||
|
2: 'Adjunct',
|
||||||
|
}
|
||||||
|
|
||||||
|
grain_category = models.IntegerField(choices=categories, default=1)
|
||||||
|
fermentable_type = models.IntegerField(choices=types, default=1)
|
||||||
|
diastatic_power = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
potential = models.DecimalField(max_digits=6, decimal_places=4)
|
||||||
|
protein = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
attenuation = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
lovibond = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
max_in_batch = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
moisture = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True)
|
||||||
|
non_fermentable = models.BooleanField(null=True, blank=True)
|
||||||
|
ibu_per_unit = models.DecimalField(max_digits=6, decimal_places=4, default=0)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class RecipeFermentable(CustomModel):
|
||||||
|
recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE)
|
||||||
|
fermentable = models.ForeignKey(Fermentable, on_delete=models.CASCADE)
|
||||||
|
quantity = models.DecimalField(max_digits=6, decimal_places=4)
|
||||||
|
|
||||||
|
class Hop(CustomIngredient):
|
||||||
|
uses = {
|
||||||
|
1: 'Bittering',
|
||||||
|
2: 'Aroma',
|
||||||
|
3: 'Both',
|
||||||
|
}
|
||||||
|
|
||||||
|
types = {
|
||||||
|
1: 'Pellet',
|
||||||
|
2: 'Leaf',
|
||||||
|
3: 'Cryo',
|
||||||
|
4: 'CO2 Extract',
|
||||||
|
}
|
||||||
|
|
||||||
|
ibu = models.DecimalField(max_digits=6, decimal_places=4, default=0)
|
||||||
|
use = models.IntegerField(choices=uses, default=1)
|
||||||
|
hop_type = models.IntegerField(choices=types, default=1)
|
||||||
|
alpha = models.DecimalField(max_digits=6, decimal_places=2, default=0)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class RecipeHop(CustomModel):
|
||||||
|
recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE)
|
||||||
|
hop = models.ForeignKey(Hop, on_delete=models.CASCADE)
|
||||||
|
quantity = models.DecimalField(max_digits=6, decimal_places=4)
|
||||||
|
|
||||||
|
class Misc(CustomIngredient):
|
||||||
|
uses = {
|
||||||
|
1: 'Mash',
|
||||||
|
2: 'Sparge',
|
||||||
|
3: 'Boil',
|
||||||
|
4: 'Flamout',
|
||||||
|
5: 'Primary',
|
||||||
|
6: 'Secondary',
|
||||||
|
7: 'Cold Crash',
|
||||||
|
8: 'Bottling',
|
||||||
|
}
|
||||||
|
|
||||||
|
types = {
|
||||||
|
1: 'Spice',
|
||||||
|
2: 'Fining',
|
||||||
|
3: 'Water Agent',
|
||||||
|
4: 'Herb',
|
||||||
|
5: 'Flavor',
|
||||||
|
6: 'Other',
|
||||||
|
}
|
||||||
|
|
||||||
|
use = models.IntegerField(choices=uses, default=1)
|
||||||
|
misc_type = models.IntegerField(choices=types, default=1)
|
||||||
|
water_adjustment = models.BooleanField(null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class RecipeMisc(CustomModel):
|
||||||
|
recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE)
|
||||||
|
misc = models.ForeignKey(Misc, on_delete=models.CASCADE)
|
||||||
|
quantity = models.DecimalField(max_digits=6, decimal_places=4)
|
||||||
|
|
||||||
|
class RecipeYeast(CustomModel):
|
||||||
|
recipe = models.ForeignKey(BatchRecipe, on_delete=models.CASCADE)
|
||||||
|
yeast = models.ForeignKey('yeast.Strain', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Mash(CustomModel):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class MashStep(CustomModel):
|
||||||
|
step_types = {
|
||||||
|
1: 'infusion',
|
||||||
|
2: 'temperature',
|
||||||
|
3: 'decoction',
|
||||||
|
}
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
step_temp = models.DecimalField(max_digits=6, decimal_places=2)
|
||||||
|
ramp_time = models.DecimalField(max_digits=6, decimal_places=2)
|
||||||
|
step_time = models.DecimalField(max_digits=6, decimal_places=2)
|
||||||
|
step_type = models.IntegerField(choices=step_types, default=1)
|
||||||
|
parent_mash = models.ForeignKey(Mash, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
Loading…
Reference in New Issue
Block a user