diff --git a/cookbook/forms.py b/cookbook/forms.py
index f4d495aed..a097146c7 100644
--- a/cookbook/forms.py
+++ b/cookbook/forms.py
@@ -70,6 +70,23 @@ class RecipeForm(forms.Form):
)
+class UnitMergeForm(forms.Form):
+ prefix = 'unit'
+
+ new_unit = forms.ModelChoiceField(
+ queryset=Unit.objects.all(),
+ widget=SelectWidget,
+ label=_('New Unit'),
+ help_text=_('New unit that other gets replaced by.'),
+ )
+ old_unit = forms.ModelChoiceField(
+ queryset=Unit.objects.all(),
+ widget=SelectWidget,
+ label=_('Old Unit'),
+ help_text=_('Unit that should be replaced.'),
+ )
+
+
class CommentForm(forms.ModelForm):
prefix = 'comment'
diff --git a/cookbook/templates/base.html b/cookbook/templates/base.html
index e025f81cb..49fc150da 100644
--- a/cookbook/templates/base.html
+++ b/cookbook/templates/base.html
@@ -107,6 +107,9 @@
class="fas fa-history"> {% trans 'Import Log' %}
{% trans 'Statistics' %}
+ {% trans 'Units & Ingredients' %}
+
diff --git a/cookbook/templates/forms/ingredients.html b/cookbook/templates/forms/ingredients.html
new file mode 100644
index 000000000..06c09dd46
--- /dev/null
+++ b/cookbook/templates/forms/ingredients.html
@@ -0,0 +1,34 @@
+{% extends "base.html" %}
+{% load django_tables2 %}
+{% load crispy_forms_tags %}
+{% load static %}
+{% load i18n %}
+
+{% block title %}{% trans "Cookbook" %}{% endblock %}
+
+{% block extra_head %}
+ {{ form.media }}
+{% endblock %}
+
+{% block content %}
+
+
{% trans 'Edit Ingredients' %}
+ {% blocktrans %}
+ The following form can be used if, accidentally, two (or more) units or ingredients where created that should be
+ the same.
+ It merges two units or ingredients and updates all recipes using them.
+ {% endblocktrans %}
+
+
+
+ {% trans 'Units' %}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/cookbook/urls.py b/cookbook/urls.py
index 0ad886e03..e62d2a67b 100644
--- a/cookbook/urls.py
+++ b/cookbook/urls.py
@@ -38,6 +38,7 @@ urlpatterns = [
path('edit/comment//', edit.CommentUpdate.as_view(), name='edit_comment'),
path('edit/recipe-book//', edit.RecipeBookUpdate.as_view(), name='edit_recipe_book'),
path('edit/plan//', edit.MealPlanUpdate.as_view(), name='edit_plan'),
+ path('edit/ingredient/', edit.edit_ingredients, name='edit_ingredient'),
path('redirect/delete///', edit.delete_redirect, name='redirect_delete'),
diff --git a/cookbook/views/edit.py b/cookbook/views/edit.py
index 36e1464a9..2165a8209 100644
--- a/cookbook/views/edit.py
+++ b/cookbook/views/edit.py
@@ -11,10 +11,11 @@ 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
-from django.utils.translation import gettext as _
+from django.utils.translation import gettext as _, ngettext
from django.views.generic import UpdateView, DeleteView
-from cookbook.forms import ExternalRecipeForm, KeywordForm, StorageForm, SyncForm, InternalRecipeForm, CommentForm, MealPlanForm
+from cookbook.forms import ExternalRecipeForm, KeywordForm, StorageForm, SyncForm, InternalRecipeForm, CommentForm, \
+ MealPlanForm, UnitMergeForm
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeIngredients, RecipeBook, \
RecipeBookEntry, MealPlan, Unit
from cookbook.provider.dropbox import Dropbox
@@ -104,7 +105,9 @@ def internal_recipe_update(request, pk):
else:
form = InternalRecipeForm(instance=recipe_instance)
- ingredients = RecipeIngredients.objects.select_related('unit__name').filter(recipe=recipe_instance).values('name', 'unit__name', 'amount')
+ 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)),
@@ -290,8 +293,29 @@ class RecipeUpdate(LoginRequiredMixin, UpdateView):
return context
-# Generic Delete views
+@login_required
+def edit_ingredients(request):
+ if request.method == "POST":
+ form = UnitMergeForm(request.POST, prefix=UnitMergeForm.prefix)
+ if form.is_valid():
+ new_unit = form.cleaned_data['new_unit']
+ old_unit = form.cleaned_data['old_unit']
+ ingredients = RecipeIngredients.objects.filter(unit=old_unit).all()
+ for i in ingredients:
+ i.unit = new_unit
+ i.save()
+ old_unit.delete()
+ messages.add_message(request, messages.SUCCESS, _('Units merged!'))
+ else:
+ messages.add_message(request, messages.WARNING, _('There was an error in your form.'))
+ else:
+ form = UnitMergeForm()
+
+ return render(request, 'forms/ingredients.html', {'form': form})
+
+
+# Generic Delete views
def delete_redirect(request, name, pk):
return redirect(('delete_' + name), pk)