Compare commits
8 Commits
83dd508f8b
...
581289c947
Author | SHA1 | Date | |
---|---|---|---|
|
581289c947 | ||
|
c4d9d9489d | ||
|
f59ec40958 | ||
|
77354bfcbd | ||
|
2e21838898 | ||
|
f5c87eb22f | ||
|
ee1cdd2a39 | ||
|
18b675af85 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ __pycache__
|
||||
brewery.sqlite
|
||||
media
|
||||
secrets.json
|
||||
.env
|
@ -1,4 +1,9 @@
|
||||
import labels
|
||||
import datetime
|
||||
from random import randint
|
||||
from django.db.models import BigIntegerField
|
||||
|
||||
|
||||
from django.urls import reverse
|
||||
|
||||
from reportlab.graphics import shapes
|
||||
@ -9,6 +14,12 @@ from config.settings import DEBUG
|
||||
|
||||
BREWFATHER_APP_ROOT = 'https://web.brewfather.app'
|
||||
|
||||
def random_with_N_digits(n):
|
||||
range_start = 10**(n-1)
|
||||
range_end = (10**n)-1
|
||||
return randint(range_start, range_end)
|
||||
|
||||
|
||||
class AveryLabel:
|
||||
"""
|
||||
test_labels = [
|
||||
@ -164,3 +175,40 @@ class AveryLabel:
|
||||
|
||||
# Save the file and we are done.
|
||||
sheet.save(render_file)
|
||||
|
||||
class DateUUIDField(BigIntegerField):
|
||||
"""
|
||||
A field which stores a Short UUID value with prepended date. This may also have
|
||||
the Boolean attribute 'auto' which will set the value on initial save to a
|
||||
new UUID value (calculated using shortuuid's default (uuid4)). Note that while all
|
||||
UUIDs are expected to be unique we enforce this with a DB constraint.
|
||||
"""
|
||||
|
||||
def __init__(self, auto=True, *args, **kwargs):
|
||||
self.auto = auto
|
||||
if auto:
|
||||
# Do not let the user edit UUIDs if they are auto-assigned.
|
||||
kwargs['editable'] = False
|
||||
kwargs['blank'] = True
|
||||
kwargs['unique'] = True # if you want to be paranoid, set unique=True in your instantiation of the field.
|
||||
|
||||
super(DateUUIDField, self).__init__(*args, **kwargs)
|
||||
|
||||
def pre_save(self, model_instance, add):
|
||||
"""
|
||||
This is used to ensure that we auto-set values if required.
|
||||
See CharField.pre_save
|
||||
"""
|
||||
value = super(DateUUIDField, self).pre_save(model_instance, add)
|
||||
if self.auto and not value:
|
||||
# Assign a new value for this attribute if required.
|
||||
x = datetime.datetime.now()
|
||||
front = x.strftime("%Y%m%d")
|
||||
value = int('{}{}'.format(front,random_with_N_digits(6)))
|
||||
setattr(model_instance, self.attname, value)
|
||||
return value
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
if self.auto:
|
||||
return None
|
||||
return super(DateUUIDField, self).formfield(**kwargs)
|
@ -72,7 +72,7 @@ MIDDLEWARE = [
|
||||
MEDIA_ROOT = '/tmp/media/'
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
STATIC_ROOT = '/tmp/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR,'sitestatic')
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
TEMPLATES = [
|
||||
|
@ -1,16 +1,16 @@
|
||||
"""
|
||||
WSGI config for django_sqlite project.
|
||||
WSGI config for testing project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
|
||||
https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_sqlite.settings")
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
||||
|
||||
application = get_wsgi_application()
|
@ -6,3 +6,4 @@ docutils==0.21.2
|
||||
django-mathfilters==1.0.0
|
||||
pylabels==1.2.1
|
||||
reportlab==4.2.0
|
||||
wiki==0.11.1
|
||||
|
@ -1,30 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load mathfilters %}
|
||||
{% block title %}Yeast Samples{% endblock %}
|
||||
{% block content %}
|
||||
<main role="main">
|
||||
|
||||
<!-- Main jumbotron for a primary marketing message or call to action -->
|
||||
<div class="jumbotron">
|
||||
<div class="container">
|
||||
<h1 class="display-3">Yeast Sample: {{ sample.id }}</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h3>{{ batch.strain.name }}</h3>
|
||||
Batch Source: {{ batch.source }}
|
||||
|
||||
|
||||
</div> <!-- /container -->
|
||||
|
||||
{% for sample in batch.remaining_samples %}
|
||||
<ul>
|
||||
<li><a href="/samples/{{ sample.id }}">{{ sample.packaging_date }}</a> Strain: {{ sample.age }} days, Viability:{{ sample.viability|mul:100|floatformat:1 }}%</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</main>
|
||||
|
||||
{% endblock %}
|
@ -6,6 +6,7 @@ from django.contrib.auth.models import User
|
||||
from django.db.models import Count
|
||||
import math
|
||||
|
||||
from config.extras import DateUUIDField
|
||||
import logging
|
||||
logger = logging.getLogger('django')
|
||||
|
||||
@ -71,7 +72,7 @@ class Batch(CustomModel):
|
||||
'PR': 'Propogated',
|
||||
'SL': 'Slurry',
|
||||
}
|
||||
|
||||
id = DateUUIDField(primary_key=True)
|
||||
parent = models.ManyToManyField('Yeast', related_name='+', blank=True)
|
||||
production_date = models.DateField()
|
||||
strain = models.ForeignKey(Strain, on_delete=models.PROTECT, default=0)
|
||||
@ -105,6 +106,7 @@ class Yeast(CustomModel):
|
||||
"""
|
||||
Store an individual sample of yeast.
|
||||
"""
|
||||
id = DateUUIDField(primary_key=True)
|
||||
batch = models.ForeignKey(Batch, on_delete=models.CASCADE)
|
||||
generation_num = models.IntegerField(default=0)
|
||||
storage = models.ForeignKey(Storage, on_delete=models.CASCADE)
|
||||
|
@ -19,7 +19,6 @@
|
||||
<p><p>
|
||||
|
||||
</div> <!-- /container -->
|
||||
{% url 'yeast:labels' batch.id %}
|
||||
<div class="container">
|
||||
<form action="{% url 'yeast:labels' batch.id %}" method="post">
|
||||
<fieldset>
|
@ -25,12 +25,26 @@
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p><p>
|
||||
Test
|
||||
<a href="{% url 'yeast:addbatch' %}">Add Batch</a>
|
||||
|
||||
<ul>
|
||||
{% for batch in object_list %}
|
||||
{% if not batch.remaining_samples %}
|
||||
<li><a href="{% url 'yeast:batch' batch.id %}">{{ batch }}</a></li>
|
||||
<ul>
|
||||
{% for sample in batch.yeast_set.all %}
|
||||
{% if sample.pitched %}<strike>{% endif %}
|
||||
<li><a href="{% url 'yeast:yeast' sample.id %}">Sample #{{ sample.id }}</a> Age: {{ sample.age }} days, Viability: {{ sample.viability|mul:100|floatformat:1 }}%</li>
|
||||
{% if sample.pitched %}</strike>{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p><p>
|
||||
<a href="{% url 'yeast:addbatch' %}">Add Batch</a><br>
|
||||
<a href="{% url 'yeast:addstrain' %}">Add Yeast Strain</a>
|
||||
</div> <!-- /container -->
|
||||
|
36
yeast/templates/yeast/sample.html
Normal file
36
yeast/templates/yeast/sample.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
{% load mathfilters %}
|
||||
{% block title %}Yeast Samples{% endblock %}
|
||||
{% block content %}
|
||||
<main role="main">
|
||||
|
||||
<!-- Main jumbotron for a primary marketing message or call to action -->
|
||||
<div class="jumbotron">
|
||||
<div class="container">
|
||||
<h1 class="display-3">Yeast Sample: {{ yeast.id }}</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h3>{{ batch.strain.name }}</h3>
|
||||
Batch Source: {{ batch.get_source_display }}<br>
|
||||
Production Date: {{ sample.batch.production_date }}
|
||||
<p><p>
|
||||
{% for sample in batch.remaining_samples %}
|
||||
<ul>
|
||||
<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>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for sample in batch.used_samples %}
|
||||
<ul>
|
||||
<li><a href="{% url 'yeast:yeast' sample.id %}">{{ sample.id }}</a></li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div> <!-- /container -->
|
||||
</main>
|
||||
|
||||
{% endblock %}
|
@ -18,9 +18,9 @@ class YeastListView(ListView):
|
||||
class BatchListView(ListView):
|
||||
model = Batch
|
||||
|
||||
def sample(request, sample_id):
|
||||
def sample(request, yeast_id):
|
||||
|
||||
sample = get_object_or_404(Yeast, pk=sample_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', {'sample': sample, 'batch':sample_batch})
|
||||
|
||||
@ -36,9 +36,7 @@ def batch_labels(request, batch_id):
|
||||
"""
|
||||
skip_count = request.POST.get("skip_count", "")
|
||||
samples = request.POST.getlist("samples", "")
|
||||
|
||||
batch = get_object_or_404(Batch, pk=batch_id)
|
||||
|
||||
to_print = list(filter(lambda d: str(d.id) in samples, batch.yeast_set.all()))
|
||||
|
||||
# Create the HttpResponse object with the appropriate PDF headers.
|
||||
@ -51,17 +49,9 @@ def batch_labels(request, batch_id):
|
||||
|
||||
labels = []
|
||||
for sample in to_print:
|
||||
# labels.append({
|
||||
# 'date': sample.batch.production_date,
|
||||
# 'name': sample.name,
|
||||
# 'manufacturer': sample.batch.strain.manufacturer.name,
|
||||
# 'id': sample.id,
|
||||
# 'blank': False,
|
||||
# 'host': request.get_host(),
|
||||
# })
|
||||
labels.append({
|
||||
'id': sample.id,
|
||||
'title': '{} {}'.format(sample.batch.strain.manufacturer.name, sample.name),
|
||||
'title': '{} {}'.format(sample.batch.strain.manufacturer.name, sample.batch.strain.name),
|
||||
'data': ['ID: {}'.format(sample.id), 'Date: {}'.format(sample.batch.production_date)],
|
||||
'blank': False,
|
||||
'host': request.get_host(),
|
||||
|
Loading…
Reference in New Issue
Block a user