mirror of
https://github.com/StefBuwalda/cal_counter.git
synced 2025-10-30 11:19:59 +00:00
Squashed commit of the following:
commit 7fe30bfebf
Author: Stef <stbuwalda@gmail.com>
Date: Mon Aug 11 14:32:53 2025 +0200
Improve FoodItem uniqueness and add name constraint
Refactored add_meal routes to check for existing FoodItems by name or barcode and improved form handling. Made barcode optional in FoodItemForm. Added a unique constraint on (name, owner_id) for FoodItem in both the model and database migrations, while retaining the (barcode, owner_id) constraint. Updated FoodItem relationship to cascade deletes.
This commit is contained in:
@@ -12,8 +12,10 @@ from flask_login import current_user
|
||||
from forms import FoodItemForm, FoodLogForm
|
||||
from application import db
|
||||
from models import FoodItem, FoodLog
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import and_, or_
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from sqlalchemy.sql.elements import BinaryExpression
|
||||
from typing import cast
|
||||
|
||||
bp = Blueprint(
|
||||
"add_meal",
|
||||
@@ -51,59 +53,23 @@ def step3(input: str):
|
||||
# Check if input is a barcode
|
||||
if input.isdigit():
|
||||
item = current_user.food_items.filter_by(barcode=input).first()
|
||||
if item is None:
|
||||
# Does not exist, add item
|
||||
return redirect(url_for("add_meal.step3_alt1", input=input))
|
||||
|
||||
else:
|
||||
# input is not a number, must be the name of the item.
|
||||
item = current_user.food_items.filter_by(name=input).first()
|
||||
if item is None:
|
||||
# Does not exist, add manually.
|
||||
return redirect(url_for("add_meal.step3_alt1", input=input))
|
||||
|
||||
if item is None:
|
||||
# Does not exist, add item
|
||||
return redirect(url_for("add_meal.step3_alt1", input=input))
|
||||
|
||||
# Track item to add and continue to next step
|
||||
session["item_id"] = item.id
|
||||
return redirect(url_for("add_meal.step4"))
|
||||
|
||||
|
||||
@bp.route("/step3_alt1/<string:input>", methods=["GET", "POST"])
|
||||
@bp.route("/step3_alt1/<string:input>", methods=["GET"])
|
||||
def step3_alt1(input: str):
|
||||
form = FoodItemForm()
|
||||
if form.validate_on_submit():
|
||||
print("[DEBUG] Valid form")
|
||||
if (
|
||||
current_user.food_items.filter_by(
|
||||
barcode=form.barcode.data
|
||||
).first()
|
||||
is None
|
||||
):
|
||||
assert form.name.data is not None
|
||||
assert form.energy.data is not None
|
||||
assert form.protein.data is not None
|
||||
assert form.carbs.data is not None
|
||||
assert form.fat.data is not None
|
||||
assert form.barcode.data is not None
|
||||
db.session.add(
|
||||
FoodItem(
|
||||
name=form.name.data,
|
||||
owner_id=current_user.id,
|
||||
energy=form.energy.data,
|
||||
protein=form.protein.data,
|
||||
carbs=form.carbs.data,
|
||||
fat=form.fat.data,
|
||||
barcode=(
|
||||
form.barcode.data
|
||||
if form.barcode.data.isdigit()
|
||||
else None
|
||||
),
|
||||
saturated_fat=form.saturated_fat.data,
|
||||
sugar=form.sugar.data,
|
||||
)
|
||||
)
|
||||
db.session.commit()
|
||||
print("[DEBUG] New item added")
|
||||
return redirect(url_for("add_meal.step3", input=form.barcode.data))
|
||||
print("[DEBUG] Invalid form")
|
||||
|
||||
if input.isdigit():
|
||||
form.barcode.data = input
|
||||
else:
|
||||
@@ -111,6 +77,56 @@ def step3_alt1(input: str):
|
||||
return render_template("add_item.html", form=form)
|
||||
|
||||
|
||||
@bp.route("/step3_alt1/<string:input>", methods=["POST"])
|
||||
def step3_alt1_post(input: str):
|
||||
form = FoodItemForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
# Form has valid input
|
||||
barcode = form.barcode.data
|
||||
name = form.name.data
|
||||
assert name
|
||||
assert form.energy.data is not None
|
||||
assert form.protein.data is not None
|
||||
assert form.carbs.data is not None
|
||||
assert form.fat.data is not None
|
||||
|
||||
# Check if name or barcode already exists
|
||||
name_filter = cast(BinaryExpression, FoodItem.name == name)
|
||||
barcode_filter = cast(BinaryExpression, FoodItem.barcode == barcode)
|
||||
filter_exp = or_(name_filter, barcode_filter)
|
||||
item = current_user.food_items.filter(filter_exp).first()
|
||||
|
||||
if item is None:
|
||||
# Item does not exist, add to DB
|
||||
barcode = (
|
||||
barcode if barcode else None
|
||||
) # Turn empty strings into None
|
||||
db.session.add(
|
||||
FoodItem(
|
||||
name=name,
|
||||
owner_id=current_user.id,
|
||||
energy=form.energy.data,
|
||||
protein=form.protein.data,
|
||||
carbs=form.carbs.data,
|
||||
fat=form.fat.data,
|
||||
barcode=barcode,
|
||||
saturated_fat=form.saturated_fat.data,
|
||||
sugar=form.sugar.data,
|
||||
)
|
||||
)
|
||||
db.session.commit()
|
||||
print("[DEBUG] New FoodItem Added")
|
||||
else:
|
||||
print(f"Item exists: {item.barcode} {item.name}")
|
||||
|
||||
# Item added or already present, return to step 3.
|
||||
return redirect(url_for("add_meal.step3", input=input))
|
||||
else:
|
||||
print("[DEBUG] Form Invalid")
|
||||
return redirect(url_for("add_meal.step3_alt1", input=input))
|
||||
|
||||
|
||||
@bp.route("/step4", methods=["GET", "POST"])
|
||||
def step4():
|
||||
if "item_id" not in session:
|
||||
|
||||
Reference in New Issue
Block a user