Update from dev branch #7

Merged
cgiacofei merged 6 commits from dev into master 2024-06-07 11:44:05 -04:00
12 changed files with 243 additions and 86 deletions

View File

@ -1,6 +1,8 @@
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from config.extras import BREWFATHER_APP_ROOT
import logging import logging
logger = logging.getLogger('django') logger = logging.getLogger('django')
@ -18,6 +20,10 @@ class Batch(CustomModel):
brewfather_name = models.CharField(max_length=500, default='name') brewfather_name = models.CharField(max_length=500, default='name')
recipe = models.ForeignKey('BatchRecipe', on_delete=models.CASCADE, default=1) recipe = models.ForeignKey('BatchRecipe', on_delete=models.CASCADE, default=1)
@property
def brewfather_url(self):
return '{}/tabs/batches/batch/{}'.format(BREWFATHER_APP_ROOT, self.brewfather_id)
def __str__(self): def __str__(self):
# 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)

View File

@ -39,8 +39,8 @@ class MaintenanceAdmin(admin.ModelAdmin):
class EquipmentAdmin(admin.ModelAdmin): class EquipmentAdmin(admin.ModelAdmin):
readonly_fields = ('id',) readonly_fields = ('id',)
list_display = ['id', 'state', 'equipment_type', 'keg_type', 'state'] list_display = ['id', 'equipment_type', 'keg_type', 'state']
list_editable = ['state', 'equipment_type', 'keg_type', 'state'] list_editable = ['state', 'state']
@admin.register(KegType) @admin.register(KegType)
class KegTypeAdmin(admin.ModelAdmin): class KegTypeAdmin(admin.ModelAdmin):

View File

@ -8,12 +8,12 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- JS, Popper.js, and jQuery --> <!-- JS, Popper.js, and jQuery -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" <!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" -->
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" <!-- integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" -->
crossorigin="anonymous"></script> <!-- crossorigin="anonymous"></script> -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
{% block script %}{% endblock %} {% block script %}{% endblock %}
<style> <style>
{% block style %}{% endblock %} {% block style %}{% endblock %}
@ -23,6 +23,15 @@
label { label {
margin-right: 10px; margin-right: 10px;
} }
.table-borderless > tbody > tr > td,
.table-borderless > tbody > tr > th,
.table-borderless > tfoot > tr > td,
.table-borderless > tfoot > tr > th,
.table-borderless > thead > tr > td,
.table-borderless > thead > tr > th {
border: none;
background-color: rgba(0,0,0, 0.0) !important;
}
</style> </style>
</head> </head>
<body> <body>
@ -90,8 +99,6 @@
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main> </main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body> </body>
{% block endscript %}{% endblock %} {% block endscript %}{% endblock %}
</html> </html>

View File

@ -2,15 +2,15 @@ from django.contrib import admin
from django.urls import reverse 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 yeast.models import Yeast, Strain, Manufacturer, Storage, Batch from yeast.models import Yeast, Strain, Manufacturer, Storage, Propogation
from yeast.forms import YeastModelForm from yeast.forms import YeastModelForm
import beer import beer
from config.extras import BREWFATHER_APP_ROOT from config.extras import BREWFATHER_APP_ROOT
class BatchInline(admin.TabularInline): class PropogationInline(admin.TabularInline):
model = Batch model = Propogation
extra = 0 extra = 0
class SampleInline(admin.TabularInline): class SampleInline(admin.TabularInline):
@ -23,11 +23,11 @@ class StrainInline(admin.TabularInline):
class ParentInline(admin.TabularInline): class ParentInline(admin.TabularInline):
verbose_name = 'Parent Samples' verbose_name = 'Parent Samples'
model = Batch.parent.through model = Propogation.parent.through
@admin.register(Yeast) @admin.register(Yeast)
class YeastAdmin(admin.ModelAdmin): class YeastAdmin(admin.ModelAdmin):
list_display = [ 'batch', 'url', 'lot_number', 'age', 'storage', 'viability', 'generation_num', 'cellcount', 'pitched', 'date_pitched', 'pitched_batch'] list_display = [ 'propogation', 'url', 'lot_number', 'age', 'storage', 'viability', 'generation_num', 'cellcount', 'pitched', 'date_pitched', 'pitched_batch']
list_editable = ['pitched', 'date_pitched', 'pitched_batch', 'lot_number'] list_editable = ['pitched', 'date_pitched', 'pitched_batch', 'lot_number']
def batch_url(self, obj): def batch_url(self, obj):
@ -43,7 +43,7 @@ class YeastAdmin(admin.ModelAdmin):
class StrainAdmin(admin.ModelAdmin): class StrainAdmin(admin.ModelAdmin):
list_display = ['name', 'long_name', 'manufacturer', 'avilable_batches'] list_display = ['name', 'long_name', 'manufacturer', 'avilable_batches']
inlines = [ inlines = [
BatchInline, PropogationInline,
] ]
list_editable = ['long_name', 'manufacturer'] list_editable = ['long_name', 'manufacturer']
@ -58,7 +58,7 @@ class StrainAdmin(admin.ModelAdmin):
urls.append('<a href="{}">{}</a>'.format(url, url_text)) urls.append('<a href="{}">{}</a>'.format(url, url_text))
return format_html(', '.join(urls)) return format_html(', '.join(urls))
avilable_batches.short_description = 'Available Batches' avilable_batches.short_description = 'Available Propogation'
@admin.register(Storage) @admin.register(Storage)
class StorageAdmin(admin.ModelAdmin): class StorageAdmin(admin.ModelAdmin):
@ -78,8 +78,8 @@ class ManufacturerAdmin(admin.ModelAdmin):
if obj.website: if obj.website:
return format_html("<a href='{url}'>{url}</a>", url=obj.website) return format_html("<a href='{url}'>{url}</a>", url=obj.website)
@admin.register(Batch) @admin.register(Propogation)
class BatchAdmin(admin.ModelAdmin): class PropogationAdmin(admin.ModelAdmin):
list_display = ['strain', 'consumed', 'source', 'parent_samples', 'production_date', 'avilable_samples', 'used_samples'] list_display = ['strain', 'consumed', 'source', 'parent_samples', 'production_date', 'avilable_samples', 'used_samples']
form = YeastModelForm form = YeastModelForm
filter_horizontal = ['parent'] filter_horizontal = ['parent']
@ -89,7 +89,7 @@ class BatchAdmin(admin.ModelAdmin):
] ]
def save_related(self, request, form, formsets, change): def save_related(self, request, form, formsets, change):
super(BatchAdmin, self).save_related(request, form, formsets, change) super(PropogationAdmin, self).save_related(request, form, formsets, change)
if form.instance.source_batch: if form.instance.source_batch:
relate_samples = [x for x in Yeast.objects.all() if x.pitched_batch==form.instance.source_batch] relate_samples = [x for x in Yeast.objects.all() if x.pitched_batch==form.instance.source_batch]
for sample in relate_samples: for sample in relate_samples:

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.urls import reverse from django.urls import reverse
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from .models import Yeast, Batch, Strain from .models import Yeast, Propogation, Strain
import logging import logging
logger = logging.getLogger('django') logger = logging.getLogger('django')
@ -30,7 +30,7 @@ class BatchAddForm(forms.ModelForm):
# create meta class # create meta class
class Meta: class Meta:
# specify model to be used # specify model to be used
model = Batch model = Propogation
# specify fields to be used # specify fields to be used
fields = [ fields = [

View File

@ -0,0 +1,22 @@
# Generated by Django 5.0.6 on 2024-06-07 15:16
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('yeast', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='batch',
options={'verbose_name': 'Propagation', 'verbose_name_plural': 'Propagations'},
),
migrations.RenameField(
model_name='yeast',
old_name='batch',
new_name='propogation',
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.0.6 on 2024-06-07 15:21
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('beer', '0001_initial'),
('yeast', '0002_alter_batch_options_rename_batch_yeast_propogation'),
]
operations = [
migrations.RenameModel(
old_name='Batch',
new_name='Propogation',
),
]

View File

@ -48,7 +48,7 @@ class Strain(CustomModel):
@property @property
def batches_available(self): def batches_available(self):
return [x for x in Batch.objects.all() if not x.consumed and x.strain==self] return [x for x in Propogation.objects.all() if not x.consumed and x.strain==self]
def __str__(self): def __str__(self):
# Return a string that represents the instance # Return a string that represents the instance
@ -68,13 +68,14 @@ class Storage(CustomModel):
return self.name return self.name
class Batch(CustomModel): class Propogation(CustomModel):
""" """
Stores a batch of :model:`yeast.Yeast` of a single :model:`yeast.Strain`. Stores a batch of :model:`yeast.Yeast` of a single :model:`yeast.Strain`.
Can be a single purchased pack, or multiple vials Can be a single purchased pack, or multiple vials
to be frozen from a starter. to be frozen from a starter.
""" """
BATCH_TYPES = { BATCH_TYPES = {
'ST': 'Store', 'ST': 'Store',
'PR': 'Propogated', 'PR': 'Propogated',
@ -89,7 +90,7 @@ class Batch(CustomModel):
notes = models.TextField(max_length=500, blank=True, null=True) notes = models.TextField(max_length=500, blank=True, null=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
super(Batch, self).save(*args, **kwargs) super(Propogation, self).save(*args, **kwargs)
if self.source_batch: if self.source_batch:
relate_samples = [x for x in Yeast.objects.all() if x.pitched_batch==self.source_batch] relate_samples = [x for x in Yeast.objects.all() if x.pitched_batch==self.source_batch]
for sample in relate_samples: for sample in relate_samples:
@ -97,19 +98,19 @@ class Batch(CustomModel):
@property @property
def age(self): def age(self):
return int(average([x.age for x in Yeast.available.all() if x.batch == self])) return int(average([x.age for x in Yeast.available.all() if x.propogation == self]))
@property @property
def max_viability(self): def max_viability(self):
return int(max([x.viability for x in Yeast.available.all() if x.batch == self]) * 100) return int(max([x.viability for x in Yeast.available.all() if x.propogation == self]) * 100)
@property @property
def min_viability(self): def min_viability(self):
return int(min([x.viability for x in Yeast.available.all() if x.batch == self]) * 100) return int(min([x.viability for x in Yeast.available.all() if x.propogation == self]) * 100)
@property @property
def generation(self): def generation(self):
return int(average([x.generation_num for x in Yeast.available.all() if x.batch == self])) return int(average([x.generation_num for x in Yeast.available.all() if x.propogation == self]))
@property @property
def beer_name(self): def beer_name(self):
@ -132,11 +133,11 @@ class Batch(CustomModel):
@property @property
def remaining_samples(self): def remaining_samples(self):
return [x for x in Yeast.available.all() if x.batch==self] return [x for x in Yeast.available.all() if x.propogation==self]
@property @property
def used_samples(self): def used_samples(self):
return [x for x in Yeast.objects.all() if x.batch==self and x.pitched] return [x for x in Yeast.objects.all() if x.propogation==self and x.pitched]
def __str__(self): def __str__(self):
# Return a string that represents the instance # Return a string that represents the instance
@ -148,7 +149,7 @@ class Yeast(CustomModel):
Store an individual sample of yeast. Store an individual sample of yeast.
""" """
id = DateUUIDField(primary_key=True) id = DateUUIDField(primary_key=True)
batch = models.ForeignKey(Batch, on_delete=models.CASCADE) propogation = models.ForeignKey(Propogation, on_delete=models.CASCADE)
generation_num = models.IntegerField(default=0) generation_num = models.IntegerField(default=0)
storage = models.ForeignKey(Storage, on_delete=models.CASCADE) storage = models.ForeignKey(Storage, on_delete=models.CASCADE)
cellcount = models.IntegerField(default=100) cellcount = models.IntegerField(default=100)
@ -163,7 +164,7 @@ class Yeast(CustomModel):
@property @property
def name(self): def name(self):
return '{} {}'.format(self.id, self.batch.strain.name) return '{} {}'.format(self.id, self.propogation.strain.name)
@property @property
def age(self): def age(self):
@ -174,7 +175,7 @@ class Yeast(CustomModel):
else: else:
end_date = timezone.now().date() end_date = timezone.now().date()
return abs((self.batch.production_date-end_date).days) return abs((self.propogation.production_date-end_date).days)
@property @property
def viability(self): def viability(self):
@ -183,13 +184,4 @@ class Yeast(CustomModel):
def __str__(self): def __str__(self):
# Return a string that represents the instance # Return a string that represents the instance
return '{} {}'.format(self.id, self.batch.strain.name) return '{} {}'.format(self.id, self.propogation.strain.name)
# class BeerBatch(CustomModel):
# brewfather_id = models.CharField(max_length=50)
# brewfather_num = models.IntegerField(default=1)
# brewfather_name = models.CharField(max_length=500, default='name')
# def __str__(self):
# # Return a string that represents the instance
# return 'BF #{num}: {name}'.format(name=self.brewfather_name, num=self.brewfather_num)

View File

@ -49,7 +49,7 @@
</fieldset> </fieldset>
</div> </div>
<div class="col-md-6 form-group"> <div class="col-md-6 form-group">
<legend>Print Selected Labels for this Batch</legend> <legend>Print Selected Labels for this Propogation</legend>
<p><p> <p><p>
<label for="skip_count">Number of labels already removed from the sheet: </label> <label for="skip_count">Number of labels already removed from the sheet: </label>
<input id="skip_count" type="number" name="skip_count" value=0 size="4"> <input id="skip_count" type="number" name="skip_count" value=0 size="4">

View File

@ -16,7 +16,7 @@ input, label {
<div class="container" id="main"> <div class="container" id="main">
<h3>Batches</h3> <h3>Yeast Propogations</h3>
<form action="{% url 'yeast:get_batch' %}" method="post"> <form action="{% url 'yeast:get_batch' %}" method="post">
{% csrf_token %} {% csrf_token %}
@ -37,7 +37,7 @@ input, label {
<div class="container m-2"> <div class="container m-2">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<label for="batch-select">Choose a batch:</label> <label for="batch-select">Choose a propogation:</label>
<select name="batch" id="batch-select" size="10" style="min-width:100%;"> <select name="batch" id="batch-select" size="10" style="min-width:100%;">
{% for batch in batches %} {% for batch in batches %}
{% if not batch.consumed %} {% if not batch.consumed %}
@ -56,7 +56,7 @@ input, label {
{% if batch.source == 'SL' %} {% if batch.source == 'SL' %}
<th>Yeast Source</th><td>{{ batch.get_source_display }} <a href="{{ batch.beer_url }}">#{{ batch.beer_num }} {{ batch.beer_name }}</a></td> <th>Yeast Source</th><td>{{ batch.get_source_display }} <a href="{{ batch.beer_url }}">#{{ batch.beer_num }} {{ batch.beer_name }}</a></td>
{% elif batch.source == 'ST' %} {% elif batch.source == 'ST' %}
<th>Batch Source</th><td>Purchased from Store</td> <th>Yeast Source</th><td>Purchased from Store</td>
{% endif %} {% endif %}
</tr> </tr>
<tr> <tr>
@ -86,7 +86,7 @@ input, label {
</div> </div>
</div> </div>
<div class="container m-2"> <div class="container m-2">
<input type="submit" value="Go to Batch Page"> <input type="submit" value="Go to Yeast Propogation Page">
</div> </div>
</div> </div>

View File

@ -2,33 +2,143 @@
{% load mathfilters %} {% load mathfilters %}
{% block title %}Yeast Samples{% endblock %} {% block title %}Yeast Samples{% endblock %}
{% block jumbotron %}Yeast Sample:{% endblock %} {% block style %}
{% block jumbotronsub %}<a href="{% url 'admin:yeast_yeast_change' sample.id %}">{{ sample.id }}</a>{% endblock %} .table td.fit,
.table th.fit {
white-space: nowrap;
width: 1%;
}
{% endblock %}
{% block jumbotron %}Yeast Sample{% endblock %}
{% block jumbotronsub %}
<table class="table table-borderless">
<tbody>
<tr><th class="fit">{{ batch.strain.manufacturer.name }} {{ batch.strain.name }}</th><td><a href="{% url 'admin:yeast_yeast_change' sample.id %}">{{ sample.id }}</a></td></tr>
<tr><th class="fit">Batch Source</th>
<td>{{ batch.get_source_display }}
{% if batch.source_batch %}
from <a href="{{ batch.beer_url }}" target="_blank" rel="noopener noreferrer">#{{ batch.beer_num }}: {{ batch.beer_name }}</a><br>
{% endif %}
</td>
</tr>
<tr><th class="fit">Production Date</th><td>{{ sample.batch.production_date }}</td></tr>
<tr><th class="fit">Storage</th>
<td>
{{ sample.storage }}
{% if sample.pitched %}
(Pitched <a href="{{ sample.pitched_batch.brewfather_url }}" target="_blank" rel="noopener noreferrer">#{{ sample.pitched_batch.brewfather_num }}: {{ sample.pitched_batch.brewfather_name }}</a>)
{% endif %}
</td>
</tr>
</tbody>
</table>
{% endblock %}
{% block content %} {% block content %}
<div class="container"> <!-- Information Header -->
<div class="container">
<h3>{{ batch.strain.name }}</h3> </div> <!-- /container -->
<b>Batch Source:</b> {{ batch.get_source_display }} <!-- End Information Header -->
{% if batch.source_batch %}
from <a href="{{ batch.beer_url }}" target="_blank" rel="noopener noreferrer">#{{ batch.beer_num }}: {{ batch.beer_name }}</a> <!-- Main Data Container -->
{% endif %}<br> <div class="container mt-4 mb-4">
<b>Production Date:</b> {{ sample.batch.production_date }}<br> <div class="row">
<!-- Tabbed Forms -->
<div class="col-lg-6" style="{% if sample.pitched %}display:none{% endif %}">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-bs-toggle="tab" href="#propogate">Propogate Sample</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#pitch">Pitch Sample</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div id="propogate" class="container tab-pane active"><br>
<!-- Sample Propogation Form -->
<div class="container" style="border:1px solid #cecece;">
<form >
<legend>Propogate Yeast Sample</legend>
<div class="mb-3">
<label for="new-samples" class="form-label"># New Samples</label>
<input type="number" class="form-control" id="new-samples" aria-describedby="numHelp">
<div id="numHelp" class="form-text">New samples will be automatically created</div>
</div>
<div class="mb-3">
<label for="parent" class="form-label">Default Storage Method</label>
<select class="form-select" id="parent" name="parent" aria-describedby="storageHelp">
<option selected>-- Choose an Option --</option>
{% for method in storage %}
<option value="{{ method.id }}">{{ method }}</option>
{% endfor %}
</select>
<div id="storageHelp" class="form-text">How will samples be stored?</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<!-- End Sample Propogation Form -->
</div>
<div id="pitch" class="container tab-pane fade"><br>
<!-- Sample Pitch Form -->
<div class="container" style="border:1px solid #cecece;">
<form >
<legend>Pitch Yeast Sample</legend>
<div class="mb-3">
<label for="beer-batch" class="form-label">Beer Batch</label>
<select class="form-select" id="beer-batch" name="beer-batch" aria-describedby="batchHelp">
<option selected>Beer Batch</option>
<option value="1">#16 So So Special</option>
<option value="2">#17 Some other beer</option>
<option value="3">#18 Another Thing</option>
</select>
<div id="batchHelp" class="form-text">Select batch of beer sample is pitched into.</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="starterCheck">
<label class="form-check-label" for="starterCheck">Pitched into starter?</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<!-- End Sample Pitch Form -->
</div>
</div>
</div>
<!-- End Tabbed Forms -->
<!-- Remain Sample List -->
<div class="col-lg-6">
{% if batch.remaining_samples %}<h4>Other Remaining Batch Samples</h4>
<ul>
{% for s in batch.remaining_samples|dictsort:"storage.name" %}
{% if s.id != sample.id %}
<li><a href="{% url 'yeast:yeast' s.id %}">{{ s.id }}</a> - {{ s.storage.name }} for {{ s.age }} days, {{ s.viability|mul:100|floatformat:1 }}%</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if batch.used_samples %}<h4>Other Samples Used</h4>
<ul>
{% for s in batch.used_samples %}
{% if s.id != sample.id %}
<li><a href="{% url 'yeast:yeast' s.id %}">{{ s.id }}</a></li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</div>
<!-- End Remain Sample List -->
</div>
</div>
<!-- End Main Data Container -->
<p><p>
{% if batch.remaining_samples %}<h4>Batch Samples Remaining</h4>
<ul>
{% for sample in batch.remaining_samples %}
<li><a href="{% url 'yeast:yeast' sample.id %}">{{ sample.id }}</a> - Storage method: {{ sample.storage.name }} for {{ sample.age }} days, Viability: {{ sample.viability|mul:100|floatformat:1 }}%</li>
{% endfor %}
</ul>
{% endif %}
{% if batch.used_samples %}<h4>Batch Samples Used</h4>
<ul>
{% for sample in batch.used_samples %}
<li><a href="{% url 'yeast:yeast' sample.id %}">{{ sample.id }}</a></li>
{% endfor %}
</ul>
{% endif %}
</div> <!-- /container -->
{% endblock %} {% endblock %}

View File

@ -6,7 +6,7 @@ from django.urls import reverse
from django.http import JsonResponse from django.http import JsonResponse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from yeast.models import Yeast, Batch, Strain from yeast.models import Yeast, Propogation, Strain
from config.extras import AveryLabel from config.extras import AveryLabel
from yeast.forms import BatchAddForm, StrainAddForm from yeast.forms import BatchAddForm, StrainAddForm
@ -18,13 +18,15 @@ class YeastListView(ListView):
model = Yeast model = Yeast
class BatchListView(ListView): class BatchListView(ListView):
model = Batch model = Propogation
def sample(request, yeast_id): def sample(request, yeast_id):
sample = get_object_or_404(Yeast, pk=yeast_id) sample = get_object_or_404(Yeast, pk=yeast_id)
sample_batch = get_object_or_404(Batch, pk=sample.batch_id) return render(request, 'yeast/sample.html', {
return render(request, 'yeast/sample.html', {'sample': sample, 'batch':sample_batch}) 'sample': sample,
'batch': get_object_or_404(Propogation, pk=sample.batch_id),
'storage': list(Storage.objects.all()),
})
# @login_required # @login_required
# def get_batches(request): # def get_batches(request):
@ -43,19 +45,19 @@ def get_batch(request):
return redirect(re_url) return redirect(re_url)
def home(request): def home(request):
return render(request, 'yeast/home.html',{'batches': Batch.objects.all, 'strains': Strain.objects.all}) return render(request, 'yeast/home.html',{'batches': Propogation.objects.all, 'strains': Strain.objects.all})
def batch(request, batch_id): def batch(request, batch_id):
""" """
Display a batch of yeast samples. Display a batch of yeast samples.
``Batch`` ``Propogation``
An instance of :model:`yeast.Batch`. An instance of :model:`yeast.Propogation`.
``Template`` ``Template``
:template:`yeast/batch.html` :template:`yeast/batch.html`
""" """
batch = get_object_or_404(Batch, pk=batch_id) batch = get_object_or_404(Propogation, pk=batch_id)
return render(request, 'yeast/batch.html', {'batch': batch}) return render(request, 'yeast/batch.html', {'batch': batch})
def batch_labels(request, batch_id): def batch_labels(request, batch_id):
@ -65,11 +67,11 @@ def batch_labels(request, batch_id):
**Context** **Context**
``Batch`` ``Batch``
An instance of :model:`yeast.Batch`. An instance of :model:`yeast.Propogation`.
""" """
skip_count = request.POST.get("skip_count", "") skip_count = request.POST.get("skip_count", "")
samples = request.POST.getlist("samples", "") samples = request.POST.getlist("samples", "")
batch = get_object_or_404(Batch, pk=batch_id) batch = get_object_or_404(Propogation, pk=batch_id)
to_print = list(filter(lambda d: str(d.id) in samples, batch.yeast_set.all())) to_print = list(filter(lambda d: str(d.id) in samples, batch.yeast_set.all()))
# Create the HttpResponse object with the appropriate PDF headers. # Create the HttpResponse object with the appropriate PDF headers.
@ -96,7 +98,7 @@ def batch_labels(request, batch_id):
return response return response
class addBatch(CreateView): class addBatch(CreateView):
model = Batch model = Propogation
form_class = BatchAddForm form_class = BatchAddForm
def get_success_url(self): def get_success_url(self):