basics of ingredient unit normalization
This commit is contained in:
parent
227d90d49d
commit
a2348f531b
2
.gitignore
vendored
2
.gitignore
vendored
@ -63,7 +63,7 @@ venv/
|
||||
|
||||
mediafiles/
|
||||
|
||||
*.sqlite3
|
||||
*.sqlite3*
|
||||
|
||||
\.idea/workspace\.xml
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="file://$PROJECT_DIR$" libraries="{pretty-checkbox}" />
|
||||
<file url="file://$PROJECT_DIR$" libraries="{jquery-3.4.1}" />
|
||||
</component>
|
||||
</project>
|
@ -1,6 +1,6 @@
|
||||
from dal import autocomplete
|
||||
|
||||
from cookbook.models import Keyword, RecipeIngredients, Recipe
|
||||
from cookbook.models import Keyword, RecipeIngredients, Recipe, Unit
|
||||
|
||||
|
||||
class KeywordAutocomplete(autocomplete.Select2QuerySetView):
|
||||
@ -40,3 +40,16 @@ class RecipeAutocomplete(autocomplete.Select2QuerySetView):
|
||||
qs = qs.filter(name__icontains=self.q)
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class UnitAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
if not self.request.user.is_authenticated:
|
||||
return Unit.objects.none()
|
||||
|
||||
qs = Unit.objects.all()
|
||||
|
||||
if self.q:
|
||||
qs = qs.filter(name__icontains=self.q)
|
||||
|
||||
return qs
|
||||
|
27
cookbook/migrations/0009_auto_20200130_1056.py
Normal file
27
cookbook/migrations/0009_auto_20200130_1056.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Generated by Django 3.0.2 on 2020-01-30 09:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0008_mealplan'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Unit',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128, unique=True)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='recipeingredients',
|
||||
name='unit_key',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='cookbook.Unit'),
|
||||
),
|
||||
]
|
28
cookbook/migrations/0010_auto_20200130_1059.py
Normal file
28
cookbook/migrations/0010_auto_20200130_1059.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Generated by Django 3.0.2 on 2020-01-30 09:59
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_ingredient_units(apps, schema_editor):
|
||||
Unit = apps.get_model('cookbook', 'Unit')
|
||||
RecipeIngredients = apps.get_model('cookbook', 'RecipeIngredients')
|
||||
|
||||
for u in RecipeIngredients.objects.values('unit').distinct():
|
||||
unit = Unit()
|
||||
unit.name = u['unit']
|
||||
unit.save()
|
||||
|
||||
for i in RecipeIngredients.objects.all():
|
||||
i.unit_key = Unit.objects.get(name=i.unit)
|
||||
i.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0009_auto_20200130_1056'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_ingredient_units),
|
||||
]
|
17
cookbook/migrations/0011_remove_recipeingredients_unit.py
Normal file
17
cookbook/migrations/0011_remove_recipeingredients_unit.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 3.0.2 on 2020-01-30 10:16
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0010_auto_20200130_1059'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='recipeingredients',
|
||||
name='unit',
|
||||
),
|
||||
]
|
18
cookbook/migrations/0012_auto_20200130_1116.py
Normal file
18
cookbook/migrations/0012_auto_20200130_1116.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.0.2 on 2020-01-30 10:16
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0011_remove_recipeingredients_unit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='recipeingredients',
|
||||
old_name='unit_key',
|
||||
new_name='unit',
|
||||
),
|
||||
]
|
@ -75,14 +75,22 @@ class Recipe(models.Model):
|
||||
return ' '.join([(x.icon + x.name) for x in self.keywords.all()])
|
||||
|
||||
|
||||
class Unit(models.Model):
|
||||
name = models.CharField(unique=True, max_length=128)
|
||||
description = models.TextField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class RecipeIngredients(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
unit = models.CharField(max_length=128)
|
||||
unit = models.ForeignKey(Unit, on_delete=models.PROTECT, null=True)
|
||||
amount = models.DecimalField(default=0, decimal_places=2, max_digits=16)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.amount) + ' ' + self.unit + ' ' + self.name
|
||||
return str(self.amount) + ' ' + str(self.unit) + ' ' + self.name
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
|
@ -20,8 +20,8 @@
|
||||
<!-- Bootstrap 4 -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
|
||||
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.js"
|
||||
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
|
||||
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
|
||||
@ -31,8 +31,8 @@
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Select2 for use with django autocomplete light -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.0.12/dist/css/select2.min.css" rel="stylesheet"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.0.12/dist/js/select2.min.js"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script>
|
||||
|
||||
<!-- Bootstrap theme for select2 -->
|
||||
<link rel="stylesheet"
|
||||
|
@ -46,7 +46,54 @@
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
<select class="form-control" id="test"></select>
|
||||
|
||||
<script>
|
||||
|
||||
$('#test').select2({
|
||||
tags: true,
|
||||
ajax: {
|
||||
url: '{% url 'dal_unit' %}',
|
||||
dataType: 'json',
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var select2Editor = function (cell, onRendered, success, cancel, editorParams) {
|
||||
|
||||
//create input element to hold select
|
||||
var editor = document.createElement("select");
|
||||
editor.setAttribute("class", "form-control");
|
||||
editor.setAttribute("style", "height: 100%");
|
||||
|
||||
onRendered(function () {
|
||||
var select_2 = $(editor);
|
||||
|
||||
select_2.select2({
|
||||
tags: true,
|
||||
ajax: {
|
||||
url: '{% url 'dal_unit' %}',
|
||||
dataType: 'json'
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
select_2.on('change', function (e) {
|
||||
success(select_2.text());
|
||||
});
|
||||
|
||||
|
||||
select_2.on('blur', function (e) {
|
||||
cancel();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//add editor to cell
|
||||
return editor;
|
||||
}
|
||||
|
||||
function selectText(node) {
|
||||
|
||||
if (document.body.createTextRange) {
|
||||
@ -73,9 +120,9 @@
|
||||
|
||||
ingredients.forEach(function (cur, i) {
|
||||
cur.delete = false
|
||||
})
|
||||
});
|
||||
|
||||
var data = ingredients
|
||||
var data = ingredients;
|
||||
|
||||
var table = new Tabulator("#ingredients-table", {
|
||||
index: "id",
|
||||
@ -85,7 +132,15 @@
|
||||
movableRows: true,
|
||||
headerSort: false,
|
||||
columns: [
|
||||
{ title: "<i class='fas fa-sort'></i>", rowHandle:true, formatter:"handle", headerSort:false, frozen:true, width:36, minWidth:36},
|
||||
{
|
||||
title: "<i class='fas fa-sort'></i>",
|
||||
rowHandle: true,
|
||||
formatter: "handle",
|
||||
headerSort: false,
|
||||
frozen: true,
|
||||
width: 36,
|
||||
minWidth: 36
|
||||
},
|
||||
{
|
||||
title: "{% trans 'Ingredient' %}",
|
||||
field: "name",
|
||||
@ -93,7 +148,7 @@
|
||||
editor: "input"
|
||||
},
|
||||
{title: "{% trans 'Amount' %}", field: "amount", validator: "required", editor: "input"},
|
||||
{title: "{% trans 'Unit' %}", field: "unit", validator: "required", editor: "input"},
|
||||
{title: "{% trans 'Unit' %}", field: "unit__name", validator: "required", editor: select2Editor},
|
||||
{
|
||||
title: "{% trans 'Delete' %}",
|
||||
field: "delete",
|
||||
@ -113,9 +168,9 @@
|
||||
})
|
||||
},
|
||||
cellClick: function (e, cell) {
|
||||
input = cell.getElement().childNodes[0]
|
||||
input.focus()
|
||||
input.select()
|
||||
//input = cell.getElement().childNodes[0]
|
||||
//input.focus()
|
||||
//input.select()
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -48,7 +48,6 @@
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for plan_key, plan_value in plan.items %}
|
||||
|
||||
<tr>
|
||||
<td colspan="7" style="text-align: center"><h5>{{ plan_value.type_name }}</h5></td>
|
||||
</tr>
|
||||
|
@ -65,4 +65,5 @@ urlpatterns = [
|
||||
|
||||
path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'),
|
||||
path('dal/ingredient/', dal.IngredientsAutocomplete.as_view(), name='dal_ingredient'),
|
||||
path('dal/unit/', dal.UnitAutocomplete.as_view(), name='dal_unit'),
|
||||
]
|
||||
|
@ -7,6 +7,7 @@ from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.files import File
|
||||
from django.db.models import Value, CharField
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import redirect, get_object_or_404, render
|
||||
from django.urls import reverse_lazy, reverse
|
||||
@ -15,7 +16,7 @@ from django.views.generic import UpdateView, DeleteView
|
||||
|
||||
from cookbook.forms import ExternalRecipeForm, KeywordForm, StorageForm, SyncForm, InternalRecipeForm, CommentForm, MealPlanForm
|
||||
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeIngredients, RecipeBook, \
|
||||
RecipeBookEntry, MealPlan
|
||||
RecipeBookEntry, MealPlan, Unit
|
||||
from cookbook.provider.dropbox import Dropbox
|
||||
from cookbook.provider.nextcloud import Nextcloud
|
||||
|
||||
@ -80,7 +81,15 @@ def internal_recipe_update(request, pk):
|
||||
ingredient.amount = float(i['amount'].replace(',', '.'))
|
||||
else:
|
||||
ingredient.amount = i['amount']
|
||||
ingredient.unit = i['unit']
|
||||
|
||||
if Unit.objects.filter(name=i['unit__name']).exists():
|
||||
ingredient.unit = Unit.objects.get(name=i['unit__name'])
|
||||
else:
|
||||
unit = Unit()
|
||||
unit.name = i['unit__name']
|
||||
unit.save()
|
||||
ingredient.unit = unit
|
||||
|
||||
ingredient.save()
|
||||
|
||||
recipe.keywords.set(form.cleaned_data['keywords'])
|
||||
@ -92,10 +101,10 @@ def internal_recipe_update(request, pk):
|
||||
else:
|
||||
form = InternalRecipeForm(instance=recipe_instance)
|
||||
|
||||
ingredients = RecipeIngredients.objects.filter(recipe=recipe_instance)
|
||||
ingredients = RecipeIngredients.objects.select_related('unit__name').filter(recipe=recipe_instance).values('name', 'unit__name', 'amount')
|
||||
|
||||
return render(request, 'forms/edit_internal_recipe.html',
|
||||
{'form': form, 'ingredients': json.dumps(list(ingredients.values())),
|
||||
{'form': form, 'ingredients': json.dumps(list(ingredients)),
|
||||
'view_url': reverse('view_recipe', args=[pk])})
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user