Remove as much list comprehension as possible.
Using aggregate functions instead.
This commit is contained in:
parent
671ea27d9f
commit
1986d9fbd0
@ -1,4 +1,5 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Sum, Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django_cryptography.fields import encrypt
|
from django_cryptography.fields import encrypt
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
@ -113,20 +114,21 @@ class Recipe(CustomModel):
|
|||||||
verbose_name = 'Recipe'
|
verbose_name = 'Recipe'
|
||||||
verbose_name_plural = 'Recipes'
|
verbose_name_plural = 'Recipes'
|
||||||
|
|
||||||
@property
|
|
||||||
def fermentables(self):
|
|
||||||
return [x for x in list(self.recipefermentable_set.all())]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fermentable_weight(self):
|
def fermentable_weight(self):
|
||||||
return sum([x.quantity for x in self.fermentables])
|
"""Weight of all fermentables attached to recipe."""
|
||||||
|
aggregate = self.recipefermentable_set.all().aggregate(Sum('quantity'))
|
||||||
|
return aggregate['quantity__sum']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hops(self):
|
def hop_weight(self):
|
||||||
return [x for x in list(self.recipehop_set.all())]
|
"""Weight of all fermentables attached to recipe."""
|
||||||
|
aggregate = self.recipehop_set.all().aggregate(Sum('quantity'))
|
||||||
|
return aggregate['quantity__sum']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def final_volume(self):
|
def final_volume(self):
|
||||||
|
"""Return final volume (after boil)."""
|
||||||
return (float(self.batch_size)
|
return (float(self.batch_size)
|
||||||
+ self.hop_water_loss
|
+ self.hop_water_loss
|
||||||
+ self.net_kettle_deadspace
|
+ self.net_kettle_deadspace
|
||||||
@ -134,44 +136,51 @@ class Recipe(CustomModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def sugar_yield(self):
|
def sugar_yield(self):
|
||||||
|
"""Return point yield of all non-mashed ingredients."""
|
||||||
ferm_yield = 0
|
ferm_yield = 0
|
||||||
|
|
||||||
sugars = (x for x in self.fermentables
|
ferms = self.recipefermentable_set.all().select_related('fermentable')
|
||||||
if x.fermentable.fermentable_type == 3) # Is sugar
|
sugars = ferms.filter(fermentable__fermentable_type=3)
|
||||||
|
|
||||||
for f in sugars:
|
for f in sugars:
|
||||||
ferm_yield += f.quantity * (f.fermentable.potential - 1) * 1000
|
ferm_yield += f.ferm_yield
|
||||||
|
|
||||||
return float(ferm_yield)
|
return float(ferm_yield)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mash_yield(self):
|
def mash_yield(self):
|
||||||
|
"""Return point yield of all mashed ingredients."""
|
||||||
mash_yield = 0
|
mash_yield = 0
|
||||||
|
|
||||||
mashed = (x for x in self.fermentables
|
ferms = self.recipefermentable_set.all().select_related('fermentable')
|
||||||
if x.fermentable.fermentable_type != 3) # Is not sugar
|
# Is not sugar (3)
|
||||||
|
mashed = ferms.filter(~Q(fermentable__fermentable_type=3))
|
||||||
|
|
||||||
for f in mashed:
|
for f in mashed:
|
||||||
mash_yield += (f.quantity * (self.efficiency / 100)
|
mash_yield += f.ferm_yield
|
||||||
* (f.fermentable.potential - 1) * 1000)
|
|
||||||
|
|
||||||
return float(mash_yield)
|
return float(mash_yield)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def original_sg(self):
|
def original_sg(self):
|
||||||
|
"""Return original gravity."""
|
||||||
total_yield = self.sugar_yield + self.mash_yield
|
total_yield = self.sugar_yield + self.mash_yield
|
||||||
return round(1 + total_yield / self.final_volume / 1000, 3)
|
gravity_points = total_yield/self.final_volume
|
||||||
|
return round(1 + gravity_points/1000, 3)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pre_boil_sg(self):
|
def pre_boil_sg(self):
|
||||||
|
"""Return pre-boil gravity."""
|
||||||
total_yield = self.sugar_yield + self.mash_yield
|
total_yield = self.sugar_yield + self.mash_yield
|
||||||
return round(1 + total_yield / (self.final_volume
|
total_water = self.final_volume+self.boil_off_gph
|
||||||
+ self.boil_off_gph) / 1000, 3)
|
gravity_points = total_yield/total_water
|
||||||
|
return round(1 + gravity_points/1000, 3)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hop_water_loss(self):
|
def hop_water_loss(self):
|
||||||
hop_absorption = .025 # gallons per ounce
|
return float(sum(
|
||||||
return sum([float(x.quantity) * hop_absorption for x in self.hops])
|
x.quantity*x.trub_volume for x in self.recipehop_set.all()
|
||||||
|
))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def net_kettle_deadspace(self):
|
def net_kettle_deadspace(self):
|
||||||
@ -206,11 +215,12 @@ class Recipe(CustomModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def ibu_tinseth(self):
|
def ibu_tinseth(self):
|
||||||
return sum([x.ibu_tinseth for x in self.hops])
|
return sum(x.ibu_tinseth for x in self.recipehop_set.all())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def srm(self):
|
def srm(self):
|
||||||
color_total = sum([x.srm for x in self.fermentables])
|
color_total = sum(x.lovibond_contributed
|
||||||
|
for x in self.recipefermentable_set.all())
|
||||||
return 1.4922*(color_total**0.6859)
|
return 1.4922*(color_total**0.6859)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -293,11 +303,20 @@ class RecipeFermentable(CustomModel):
|
|||||||
return float(100 * self.quantity / self.recipe.fermentable_weight)
|
return float(100 * self.quantity / self.recipe.fermentable_weight)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def srm(self):
|
def lovibond_contributed(self):
|
||||||
srm_calc = (float(self.fermentable.lovibond)
|
srm_calc = (float(self.fermentable.lovibond)
|
||||||
* float(self.quantity) / self.recipe.final_volume)
|
* float(self.quantity) / self.recipe.final_volume)
|
||||||
return round(srm_calc, 1)
|
return round(srm_calc, 1)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ferm_yield(self):
|
||||||
|
potential_yield = self.quantity * (self.fermentable.potential-1) * 1000
|
||||||
|
|
||||||
|
if self.fermentable.fermentable_type == 3:
|
||||||
|
return potential_yield
|
||||||
|
else:
|
||||||
|
return potential_yield * (self.recipe.efficiency/100)
|
||||||
|
|
||||||
|
|
||||||
class Hop(CustomIngredient):
|
class Hop(CustomIngredient):
|
||||||
uses = {
|
uses = {
|
||||||
@ -345,22 +364,31 @@ class RecipeHop(CustomModel):
|
|||||||
4: 1.4, # CO2 Extract
|
4: 1.4, # CO2 Extract
|
||||||
}
|
}
|
||||||
|
|
||||||
ibu = 0
|
hop_bonus = type_bonus[self.hop.hop_type]
|
||||||
|
|
||||||
average_wort_sg = (((self.recipe.pre_boil_sg - 1)
|
average_wort_sg = (((self.recipe.pre_boil_sg-1)
|
||||||
+ (self.recipe.original_sg - 1)) / 2)
|
+ (self.recipe.original_sg-1)) / 2)
|
||||||
|
|
||||||
if self.use == 1:
|
if self.use == 1:
|
||||||
conc = (((float(self.hop.alpha) / 100)
|
conc = (float((self.hop.alpha/100) * self.quantity)
|
||||||
* float(self.quantity))
|
* 7490/self.recipe.final_volume)
|
||||||
* 7490 / self.recipe.final_volume)
|
util = (hop_bonus*1.65*0.000125**average_wort_sg
|
||||||
util = ((type_bonus[self.hop.hop_type]
|
* ((1-2.71828182845904**(-0.04*self.time)) / 4.15))
|
||||||
* 1.65 * (0.000125**average_wort_sg))
|
|
||||||
* ((1-2.71828182845904**(-0.04 * self.time))/4.15))
|
|
||||||
ibu = conc * util
|
ibu = conc * util
|
||||||
|
else:
|
||||||
|
ibu = 0
|
||||||
|
|
||||||
return float(ibu)
|
return float(ibu)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def trub_volume(self):
|
||||||
|
if self.hop.hop_type == 1:
|
||||||
|
return self.recipe.equipment.pellet_hop_trub
|
||||||
|
elif self.hop.hop_type in [2, 3]:
|
||||||
|
return self.recipe.equipment.leaf_hop_trub
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
class Misc(CustomIngredient):
|
class Misc(CustomIngredient):
|
||||||
uses = {
|
uses = {
|
||||||
|
@ -24,7 +24,7 @@ font-size: .8em;
|
|||||||
{% block jumbotronsub %}
|
{% block jumbotronsub %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg d-flex justify-content-between" style="border:1px solid #cecece; margin-right:.5em; margin-left:.5em">
|
<div class="col-lg d-flex justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<div class="container-beer"><img src="{% static "beer_back.png" %}" alt="" class="img-responsive d-none d-sm-block"></div>
|
<div class="container-beer"><img src="{% static "beer_back.png" %}" alt="" class="img-responsive d-none d-sm-block"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -37,7 +37,7 @@ font-size: .8em;
|
|||||||
<dd>All Grain</dd>
|
<dd>All Grain</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4" style="border:1px solid #cecece; margin-right:.5em; margin-left:.5em">
|
<div class="col-lg-4">
|
||||||
<div class="d-flex justify-content-between bg-dark text-white">
|
<div class="d-flex justify-content-between bg-dark text-white">
|
||||||
<div class="text-truncate ms-1 my-1">{{ recipe.equipment.name }}</div>
|
<div class="text-truncate ms-1 my-1">{{ recipe.equipment.name }}</div>
|
||||||
<div>
|
<div>
|
||||||
@ -59,7 +59,7 @@ font-size: .8em;
|
|||||||
<dd>{{ recipe.efficiency|floatformat:2 }} %</dd>
|
<dd>{{ recipe.efficiency|floatformat:2 }} %</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-3" style="border:1px solid #cecece; margin-right:.5em; margin-left:.5em">
|
<div class="col-xl-3">
|
||||||
Style Data
|
Style Data
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -76,7 +76,7 @@ font-size: .8em;
|
|||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="d-flex justify-content-between bg-dark text-white">
|
<div class="d-flex justify-content-between bg-dark text-white">
|
||||||
<div class="ms-2 my-1">Fermentables ({{ fermentable_weight|floatformat:2 }} lbs)</div>
|
<div class="ms-2 my-1">Fermentables ({{ recipe.fermentable_weight|floatformat:2 }} lbs)</div>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="btn btn-dark btn-sm"><b>%</b></button>
|
<button type="button" class="btn btn-dark btn-sm"><b>%</b></button>
|
||||||
<button type="button" class="btn btn-dark btn-sm"><b>OG</b></button>
|
<button type="button" class="btn btn-dark btn-sm"><b>OG</b></button>
|
||||||
@ -115,7 +115,7 @@ font-size: .8em;
|
|||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="d-flex justify-content-between bg-dark text-white">
|
<div class="d-flex justify-content-between bg-dark text-white">
|
||||||
<div class="ms-2 my-1">Hops ({{ hop_weight|floatformat:2 }} oz)</div>
|
<div class="ms-2 my-1">Hops ({{ recipe.hop_weight|floatformat:2 }} oz)</div>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="btn btn-dark btn-sm"><b>IBU</b></button>
|
<button type="button" class="btn btn-dark btn-sm"><b>IBU</b></button>
|
||||||
<button type="button" class="btn btn-dark btn-sm"><i class="fa fa-plus"></i><b>ADD</b></button>
|
<button type="button" class="btn btn-dark btn-sm"><i class="fa fa-plus"></i><b>ADD</b></button>
|
||||||
|
@ -46,8 +46,6 @@ def view_recipe(request, recipe_id):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
'recipe': recipe,
|
'recipe': recipe,
|
||||||
'fermentable_weight': sum([x.quantity for x in recipe.fermentables]),
|
|
||||||
'hop_weight': sum([x.quantity for x in recipe.hops]),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, 'beer/recipe.html', context)
|
return render(request, 'beer/recipe.html', context)
|
||||||
|
Loading…
Reference in New Issue
Block a user