1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-11-07 07:29:45 +01:00

Add field 'traces' for model Food

This commit is contained in:
Ehouarn
2025-11-02 18:43:33 +01:00
parent 4f016fed38
commit 48b1ef9ec8
5 changed files with 68 additions and 8 deletions

View File

@@ -55,7 +55,7 @@ class BasicFoodForms(forms.ModelForm):
class Meta:
model = BasicFood
fields = ('name', 'owner', 'date_type', 'expiry_date', 'allergens', 'order',)
fields = ('name', 'owner', 'date_type', 'expiry_date', 'allergens', 'traces', 'order',)
widgets = {
"owner": Autocomplete(
model=Club,
@@ -98,7 +98,7 @@ class BasicFoodUpdateForms(forms.ModelForm):
"""
class Meta:
model = BasicFood
fields = ('name', 'owner', 'date_type', 'expiry_date', 'end_of_life', 'is_ready', 'order', 'allergens')
fields = ('name', 'owner', 'date_type', 'expiry_date', 'end_of_life', 'is_ready', 'order', 'allergens', 'traces')
widgets = {
"owner": Autocomplete(
model=Club,

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.6 on 2025-11-02 17:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('food', '0004_alter_foodtransaction_order'),
]
operations = [
migrations.AddField(
model_name='food',
name='traces',
field=models.ManyToManyField(blank=True, related_name='food_with_traces', to='food.allergen', verbose_name='traces'),
),
]

View File

@@ -53,6 +53,13 @@ class Food(PolymorphicModel):
verbose_name=_('allergens'),
)
traces = models.ManyToManyField(
Allergen,
blank=True,
verbose_name=_('traces'),
related_name='food_with_traces'
)
expiry_date = models.DateTimeField(
verbose_name=_('expiry date'),
null=False,
@@ -91,6 +98,19 @@ class Food(PolymorphicModel):
if old_allergens != list(parent.allergens.all()):
parent.save(old_allergens=old_allergens)
@transaction.atomic
def update_traces(self):
# update parents
for parent in self.transformed_ingredient_inv.iterator():
old_traces = list(parent.traces.all()).copy()
parent.traces.clear()
for child in parent.ingredients.iterator():
if child.pk != self.pk:
parent.traces.set(parent.traces.union(child.traces.all()))
parent.traces.set(parent.traces.union(self.traces.all()))
if old_traces != list(parent.traces.all()):
parent.save(old_traces=old_traces)
def update_expiry_date(self):
# update parents
for parent in self.transformed_ingredient_inv.iterator():
@@ -142,6 +162,10 @@ class BasicFood(Food):
and list(self.allergens.all()) != kwargs['old_allergens']):
self.update_allergens()
if ('old_traces' in kwargs
and list(self.traces.all()) != kwargs['old_traces']):
self.update_traces()
# Expiry date
if ((self.expiry_date != old_food.expiry_date
and self.date_type == 'DLC')
@@ -214,7 +238,7 @@ class TransformedFood(Food):
created = self.pk is None
if not created:
# Check if important fields are updated
update = {'allergens': False, 'expiry_date': False}
update = {'allergens': False, 'traces': False, 'expiry_date': False}
old_food = Food.objects.select_for_update().get(pk=self.pk)
if not hasattr(self, "_force_save"):
# Allergens
@@ -224,6 +248,10 @@ class TransformedFood(Food):
and list(self.allergens.all()) != kwargs['old_allergens']):
update['allergens'] = True
if ('old_traces' in kwargs
and list(self.traces.all()) != kwargs['old_traces']):
update['traces'] = True
# Expiry date
update['expiry_date'] = (self.shelf_life != old_food.shelf_life
or self.creation_date != old_food.creation_date)
@@ -234,6 +262,7 @@ class TransformedFood(Food):
if ('old_ingredients' in kwargs
and list(self.ingredients.all()) != list(kwargs['old_ingredients'])):
update['allergens'] = True
update['traces'] = True
update['expiry_date'] = True
# it's preferable to keep a queryset but we allow list too
@@ -243,6 +272,8 @@ class TransformedFood(Food):
self.check_cycle(self.ingredients.all().difference(kwargs['old_ingredients']), self, [])
if update['allergens']:
self.update_allergens()
if update['traces']:
self.update_traces()
if update['expiry_date']:
self.update_expiry_date()
@@ -254,6 +285,7 @@ class TransformedFood(Food):
for child in self.ingredients.iterator():
self.allergens.set(self.allergens.union(child.allergens.all()))
self.traces.set(self.traces.union(child.traces.all()))
if not (child.polymorphic_ctype.model == 'basicfood' and child.date_type == 'DDM'):
self.expiry_date = min(self.expiry_date, child.expiry_date)
return super().save(force_insert=False, force_update=force_update, using=using, update_fields=update_fields)

View File

@@ -32,7 +32,7 @@ class FoodTable(tables.Table):
class Meta:
model = Food
template_name = 'django_tables2/bootstrap4.html'
fields = ('name', 'owner', 'qr_code_numbers', 'allergens', 'date', 'expiry_date')
fields = ('name', 'owner', 'qr_code_numbers', 'allergens', 'traces', 'date', 'expiry_date')
row_attrs = {
'class': 'table-row',
'data-href': lambda record: 'detail/' + str(record.pk),

View File

@@ -235,6 +235,8 @@ class BasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView):
for field in context['form'].fields:
if field == 'allergens':
context['form'].fields[field].initial = getattr(food, field).all()
elif field == 'traces':
context['form'].fields[field].initial = getattr(food, field).all()
else:
context['form'].fields[field].initial = getattr(food, field)
@@ -294,6 +296,7 @@ class ManageIngredientsView(LoginRequiredMixin, UpdateView):
def form_valid(self, form):
old_ingredients = list(self.object.ingredients.all()).copy()
old_allergens = list(self.object.allergens.all()).copy()
old_traces = list(self.object.traces.all()).copy()
self.object.ingredients.clear()
for i in range(self.object.ingredients.all().count() + 1 + MAX_FORMS):
prefix = 'form-' + str(i) + '-'
@@ -320,13 +323,15 @@ class ManageIngredientsView(LoginRequiredMixin, UpdateView):
# We recalculate new expiry date and allergens
self.object.expiry_date = self.object.creation_date + self.object.shelf_life
self.object.allergens.clear()
self.object.traces.clear()
for ingredient in self.object.ingredients.iterator():
if not (ingredient.polymorphic_ctype.model == 'basicfood' and ingredient.date_type == 'DDM'):
self.object.expiry_date = min(self.object.expiry_date, ingredient.expiry_date)
self.object.allergens.set(self.object.allergens.union(ingredient.allergens.all()))
self.object.tracese.set(self.object.traces.union(ingredient.traces.all()))
self.object.save(old_ingredients=old_ingredients, old_allergens=old_allergens)
self.object.save(old_ingredients=old_ingredients, old_allergens=old_allergens, old_traces=old_traces)
return HttpResponseRedirect(self.get_success_url())
def get_context_data(self, *args, **kwargs):
@@ -378,13 +383,15 @@ class AddIngredientView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
for meal in meals:
old_ingredients = list(meal.ingredients.all()).copy()
old_allergens = list(meal.allergens.all()).copy()
old_traces = list(meal.traces.all()).copy()
meal.ingredients.add(self.object.pk)
# update allergen and expiry date if necessary
if not (self.object.polymorphic_ctype.model == 'basicfood'
and self.object.date_type == 'DDM'):
meal.expiry_date = min(meal.expiry_date, self.object.expiry_date)
meal.allergens.set(meal.allergens.union(self.object.allergens.all()))
meal.save(old_ingredients=old_ingredients, old_allergens=old_allergens)
meal.traces.set(meal.traces.union(self.object.traces.all()))
meal.save(old_ingredients=old_ingredients, old_allergens=old_allergens, old_traces=old_traces)
if 'fully_used' in form.data:
if not self.object.end_of_life:
self.object.end_of_life = _(f'Food fully used in : {meal.name}')
@@ -414,6 +421,7 @@ class FoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
form.instance.creater = self.request.user
food = Food.objects.get(pk=self.kwargs['pk'])
old_allergens = list(food.allergens.all()).copy()
old_traces = list(food.traces.all()).copy()
if food.polymorphic_ctype.model == 'transformedfood':
old_ingredients = food.ingredients.all()
@@ -427,7 +435,7 @@ class FoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
if food.polymorphic_ctype.model == 'transformedfood':
form.instance.save(old_ingredients=old_ingredients)
else:
form.instance.save(old_allergens=old_allergens)
form.instance.save(old_allergens=old_allergens, old_traces=old_traces)
return ans
def get_form_class(self, **kwargs):
@@ -460,7 +468,7 @@ class FoodDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
fields = ["name", "owner", "expiry_date", "allergens", "is_ready", "end_of_life", "order"]
fields = ["name", "owner", "expiry_date", "allergens", "traces", "is_ready", "end_of_life", "order"]
fields = dict([(field, getattr(self.object, field)) for field in fields])
if fields["is_ready"]:
@@ -469,6 +477,8 @@ class FoodDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
fields["is_ready"] = _("No")
fields["allergens"] = ", ".join(
allergen.name for allergen in fields["allergens"].all())
fields["traces"] = ", ".join(
trace.name for trace in fields["traces"].all())
context["fields"] = [(
Food._meta.get_field(field).verbose_name.capitalize(),