From a933310db743bd0a7aade4958550e328e968ecc6 Mon Sep 17 00:00:00 2001 From: Jan Peterka Date: Wed, 21 Oct 2020 10:14:39 +0200 Subject: [PATCH 1/6] Add pagination macro --- app/templates/macros/_pagination.html.j2 | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 app/templates/macros/_pagination.html.j2 diff --git a/app/templates/macros/_pagination.html.j2 b/app/templates/macros/_pagination.html.j2 new file mode 100644 index 00000000..f6a00427 --- /dev/null +++ b/app/templates/macros/_pagination.html.j2 @@ -0,0 +1,34 @@ +{% macro pagination(pagination, view_page) %} + +
+ + {% if pagination.pages > 0 %} + << + {% endif %} + + {% if pagination.has_prev %} + Předchozí + {% endif %} + + {% for page_num in pagination.iter_pages() %} + {% if page_num %} + {% if page_num != pagination.page %} + {{ page_num }} + {% else %} + {{ page_num }} + {% endif %} + {% else %} + + {% endif %} + {% endfor %} + + {% if pagination.has_next %} + Další + {% endif %} + + {% if pagination.pages > 0 %} + >> + {% endif %} +
+ +{% endmacro %} \ No newline at end of file From 5b86672976a90ce8eb8f461067a96be41658c18b Mon Sep 17 00:00:00 2001 From: Jan Peterka Date: Wed, 21 Oct 2020 10:17:36 +0200 Subject: [PATCH 2/6] Add pagination to cookbook:index --- app/controllers/cookbook.py | 5 +++-- app/models/recipes.py | 9 +++++++++ app/templates/cookbook/index.html.j2 | 5 ++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/controllers/cookbook.py b/app/controllers/cookbook.py index f5b764c3..ebe8d33c 100644 --- a/app/controllers/cookbook.py +++ b/app/controllers/cookbook.py @@ -1,6 +1,6 @@ from app.models.recipes import Recipe -from flask import redirect, url_for +from flask import redirect, request, url_for from flask_login import current_user @@ -19,4 +19,5 @@ def before_index(self): ) ) - self.recipes = Recipe.public_recipes() + page = request.args.get("page", 1, type=int) + self.recipes = Recipe.public_recipes_paginated(page, 30) diff --git a/app/models/recipes.py b/app/models/recipes.py index f13c8a51..51996d4f 100644 --- a/app/models/recipes.py +++ b/app/models/recipes.py @@ -89,6 +89,15 @@ def public_recipes(): ) # noqa: E712 return recipes + @staticmethod + def public_recipes_paginated(page, items_per_page=20): + recipes = ( + db.session.query(Recipe) + .filter(Recipe.is_shared == True) + .paginate(page, items_per_page, False) + ) # noqa: E712 + return recipes + def create_and_save(self, ingredients): db.session.add(self) db.session.flush() diff --git a/app/templates/cookbook/index.html.j2 b/app/templates/cookbook/index.html.j2 index d4f5610e..2402d63f 100644 --- a/app/templates/cookbook/index.html.j2 +++ b/app/templates/cookbook/index.html.j2 @@ -26,7 +26,7 @@ autor*ka - {% for recipe in recipes: %} + {% for recipe in recipes.items: %} {{ recipe.name }} {# @@ -41,6 +41,9 @@ {% endfor %} + + {% from "macros/_pagination.html.j2" import pagination %} + {{ pagination(recipes, view_page="CookbookView:index") }} {% endblock %} From 176c61ce713c8231ac1eb8067693788444e86746 Mon Sep 17 00:00:00 2001 From: Jan Peterka Date: Wed, 21 Oct 2020 10:59:22 +0200 Subject: [PATCH 3/6] Hide pagination --- app/controllers/cookbook.py | 10 +++++++--- app/templates/cookbook/index.html.j2 | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/controllers/cookbook.py b/app/controllers/cookbook.py index ebe8d33c..0033bff1 100644 --- a/app/controllers/cookbook.py +++ b/app/controllers/cookbook.py @@ -1,6 +1,8 @@ from app.models.recipes import Recipe -from flask import redirect, request, url_for +from flask import redirect, url_for + +# from flask import request from flask_login import current_user @@ -19,5 +21,7 @@ def before_index(self): ) ) - page = request.args.get("page", 1, type=int) - self.recipes = Recipe.public_recipes_paginated(page, 30) + # page = request.args.get("page", 1, type=int) + # self.recipe_pagination = Recipe.public_recipes_paginated(page, 30) + # self.recipes = self.recipe_pagination.items + self.recipes = Recipe.public_recipes() diff --git a/app/templates/cookbook/index.html.j2 b/app/templates/cookbook/index.html.j2 index 2402d63f..825e506d 100644 --- a/app/templates/cookbook/index.html.j2 +++ b/app/templates/cookbook/index.html.j2 @@ -26,7 +26,7 @@ autor*ka - {% for recipe in recipes.items: %} + {% for recipe in recipes: %} {{ recipe.name }} {# @@ -42,8 +42,8 @@ - {% from "macros/_pagination.html.j2" import pagination %} - {{ pagination(recipes, view_page="CookbookView:index") }} + {# {% from "macros/_pagination.html.j2" import pagination %} #} + {# {{ pagination(recipe_pagination, view_page="CookbookView:index") }} #} {% endblock %} From 1317633d9f9c034e6fb535816e6b57505af38a82 Mon Sep 17 00:00:00 2001 From: Jan Peterka Date: Mon, 9 Nov 2020 22:31:20 +0100 Subject: [PATCH 4/6] Add ratio and its calculation --- app/controllers/admin.py | 10 ++++++- app/controllers/files.py | 2 +- app/helpers/calculations.py | 29 +++++++++++++++++++ app/models/base_mixin.py | 31 +++++++++++++-------- app/models/recipes.py | 17 +++++++---- migrations/versions/2020_11_09_add_ratio.py | 28 +++++++++++++++++++ 6 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 migrations/versions/2020_11_09_add_ratio.py diff --git a/app/controllers/admin.py b/app/controllers/admin.py index 3716454a..4564dc28 100644 --- a/app/controllers/admin.py +++ b/app/controllers/admin.py @@ -1,4 +1,4 @@ -# from flask import redirect, url_for +from flask import redirect # from flask_login import current_user @@ -31,3 +31,11 @@ def index(self): self.test = User.load_all() return self.template() + + def update_recipe_ratios(self): + recipes = Recipe.load_all() + + for recipe in recipes: + recipe.update_ratio() + + return redirect("/admin/") diff --git a/app/controllers/files.py b/app/controllers/files.py index 75bb7f7e..d2c6a4d2 100644 --- a/app/controllers/files.py +++ b/app/controllers/files.py @@ -22,7 +22,7 @@ def show(self, hash_value): def delete(self, id): file = File.load(id) if file.can_current_user_delete: - file.delete() + file.remove() else: flash("Nemáte právo toto foto smazat.", "error") return redirect(request.referrer) diff --git a/app/helpers/calculations.py b/app/helpers/calculations.py index 3a53ca8a..62661204 100644 --- a/app/helpers/calculations.py +++ b/app/helpers/calculations.py @@ -5,6 +5,8 @@ from sympy import poly from sympy.solvers import solvers +import math + # CALCULATE RECIPE def calculate_recipe(ingredients, diet): @@ -198,3 +200,30 @@ def calculate_recipe(ingredients, diet): diet.expire() return {"ingredients": ingredients, "totals": totals} + + +def calculate_ratio_for_recipe(recipe): + totals = types.SimpleNamespace() + metrics = ["calorie", "sugar", "fat", "protein"] + + totals.amount = 0 + + for ingredient in recipe.ingredients: + ingredient.amount = round(ingredient.load_amount_by_recipe(recipe.id), 2) + for metric in metrics: + value = getattr(totals, metric, 0) + ing_value = getattr(ingredient, metric) + setattr(totals, metric, value + (ingredient.amount * ing_value)) + + totals.amount += ingredient.amount + + for metric in metrics: + value = getattr(totals, metric) + setattr(totals, metric, math.floor(value) / 100) + + totals.amount = math.floor(totals.amount) + + totals.ratio = ( + math.floor((totals.fat / (totals.protein + totals.sugar)) * 100) / 100 + ) + return totals.ratio diff --git a/app/models/base_mixin.py b/app/models/base_mixin.py index d21239e8..2ee5fc34 100644 --- a/app/models/base_mixin.py +++ b/app/models/base_mixin.py @@ -66,14 +66,9 @@ def created_recently(cls, days=30): # DATABASE OPERATIONS - def edit(self, **kw): - try: - db.session.commit() - return True - except Exception as e: - db.session.rollback() - application.logger.error("Edit error: {}".format(e)) - return False + # This is more Crud + # def create(self, **kw): + # return self.save(**kw) def save(self, **kw): """Saves (new) object @@ -87,6 +82,23 @@ def save(self, **kw): application.logger.error("Save error: {}".format(e)) return False + # This is more crUd + # def update(self, **kw): + # return self.edit(**kw) + + def edit(self, **kw): + try: + db.session.commit() + return True + except Exception as e: + db.session.rollback() + application.logger.error("Edit error: {}".format(e)) + return False + + # This is more cruD + # def delete(self, **kw): + # return self.remove(**kw) + def remove(self, **kw): """Deletes object """ @@ -99,9 +111,6 @@ def remove(self, **kw): application.logger.error("Remove error: {}".format(e)) return False - def delete(self, **kw): - return self.remove(**kw) - def expire(self, **kw): """Dumps database changes """ diff --git a/app/models/recipes.py b/app/models/recipes.py index 01e64168..e27af4c4 100644 --- a/app/models/recipes.py +++ b/app/models/recipes.py @@ -2,11 +2,14 @@ import math import types +from flask_login import current_user + from app import db # from app import cache -from flask_login import current_user +from app.helpers.calculations import calculate_ratio_for_recipe + from app.models.item_mixin import ItemMixin @@ -38,6 +41,8 @@ class Recipe(db.Model, ItemMixin): order_by="Ingredient.name", ) + ratio = db.Column(db.Float) + has_daily_plans = db.relationship("DailyPlanHasRecipes", back_populates="recipe") @staticmethod @@ -113,6 +118,12 @@ def remove(self): db.session.commit() return True + def update_ratio(self): + if not self.ratio: + ratio = calculate_ratio_for_recipe(self) + self.ratio = ratio + self.edit() + def toggle_shared(self): self.is_shared = not self.is_shared self.edit() @@ -165,10 +176,6 @@ def totals(self): ) return totals - @property - def ratio(self): - return self.totals.ratio - @property def values(self): values = types.SimpleNamespace() diff --git a/migrations/versions/2020_11_09_add_ratio.py b/migrations/versions/2020_11_09_add_ratio.py new file mode 100644 index 00000000..b2f95458 --- /dev/null +++ b/migrations/versions/2020_11_09_add_ratio.py @@ -0,0 +1,28 @@ +"""Add ratio to recipe + +Revision ID: faddf34671a1 +Revises: 0e33f7c6d78b +Create Date: 2020-11-09 21:51:51.689760 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "faddf34671a1" +down_revision = "0e33f7c6d78b" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("recipes", sa.Column("ratio", sa.Float(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("recipes", "ratio") + # ### end Alembic commands ### From cac8def9abf4202f56914384245300405d023340 Mon Sep 17 00:00:00 2001 From: Jan Peterka Date: Mon, 9 Nov 2020 22:32:22 +0100 Subject: [PATCH 5/6] Add part of recipe filtering --- app/controllers/cookbook.py | 62 ++++++++++++++++------------ app/helpers/formaters.py | 10 +++++ app/models/recipes.py | 25 +++++++++++ app/templates/cookbook/index.html.j2 | 2 +- 4 files changed, 72 insertions(+), 27 deletions(-) diff --git a/app/controllers/cookbook.py b/app/controllers/cookbook.py index 9df5a1d2..4f50c07f 100644 --- a/app/controllers/cookbook.py +++ b/app/controllers/cookbook.py @@ -12,6 +12,8 @@ from .extended_flask_view import ExtendedFlaskView from .forms.cookbook_filter import CookbookFilterForm +from app.helpers.formaters import coma_to_float + class CookbookView(ExtendedFlaskView): template_folder = "cookbook" @@ -21,10 +23,32 @@ def before_index(self): message = texts.cookbook.not_logged_in return redirect(url_for("CookbookView:not_logged_in", message=message)) + # Get filters from form/args + ratio_from = coma_to_float(request.args.get("ratio_from", None)) + ratio_to = coma_to_float(request.args.get("ratio_to", None)) + + if request.args.get("with_reaction", "n") == "y": + with_reaction = True + else: + with_reaction = False + + if request.args.get("ingredient_name", "--všechny--") != "--všechny--": + ingredient_name = request.args.get("ingredient_name", None) + else: + ingredient_name = None + # page = request.args.get("page", 1, type=int) # self.recipe_pagination = Recipe.public_recipes_paginated(page, 30) # self.recipes = self.recipe_pagination.items - self.recipes = Recipe.public_recipes() + self.recipes = Recipe.get_filtered_paginated_public_recipes( + 1, + filters={ + "ratio_from": ratio_from, + "ratio_to": ratio_to, + "with_reaction": with_reaction, + }, + ) + # Get values for filters ingredients = [x.ingredients for x in self.recipes] flatten_ingredients = [y for x in ingredients for y in x] @@ -33,25 +57,11 @@ def before_index(self): self.ingredient_names.extend(list(set(ingredient_names))) self.ingredient_names.sort() - if request.method == "GET": - self.form = CookbookFilterForm(ingredient_names=self.ingredient_names) - else: - self.form = CookbookFilterForm( - request.form, ingredient_names=self.ingredient_names - ) - - # Get filters from request - ingredient_name = None - ratio_from = None - ratio_to = None - with_reaction = None - - if request.method == "POST": - if not self.form.ingredient_name.data == "--všechny--": - ingredient_name = self.form.ingredient_name.data - ratio_from = self.form.ratio_from.data - ratio_to = self.form.ratio_to.data - with_reaction = self.form.with_reaction.data + self.form = CookbookFilterForm(ingredient_names=self.ingredient_names) + self.form.ratio_from.data = ratio_from + self.form.ratio_to.data = ratio_to + self.form.with_reaction.data = with_reaction + self.form.ingredient_name.data = ingredient_name # Filter recipes if ingredient_name: @@ -59,14 +69,14 @@ def before_index(self): x for x in self.recipes if ingredient_name in x.concat_ingredients ] - if ratio_from: - self.recipes = [x for x in self.recipes if x.ratio >= ratio_from] + # if ratio_from: + # self.recipes = [x for x in self.recipes if x.ratio >= ratio_from] - if ratio_to: - self.recipes = [x for x in self.recipes if x.ratio <= ratio_to] + # if ratio_to: + # self.recipes = [x for x in self.recipes if x.ratio <= ratio_to] - if with_reaction: - self.recipes = [x for x in self.recipes if x.has_reaction] + # if with_reaction: + # self.recipes = [x for x in self.recipes if x.has_reaction] @route("/", methods=["GET", "POST"]) def index(self): diff --git a/app/helpers/formaters.py b/app/helpers/formaters.py index a13de4f2..fdb5fb90 100644 --- a/app/helpers/formaters.py +++ b/app/helpers/formaters.py @@ -4,3 +4,13 @@ # private def parse_date(date): return datetime.datetime.strptime(date, "%Y-%m-%d").date() + + +def coma_to_float(string): + if string is None: + return None + string = string.replace(",", ".") + try: + return float(string) + except Exception: + return None diff --git a/app/models/recipes.py b/app/models/recipes.py index e27af4c4..77cdc200 100644 --- a/app/models/recipes.py +++ b/app/models/recipes.py @@ -2,6 +2,7 @@ import math import types +from sqlalchemy import or_ from flask_login import current_user from app import db @@ -95,6 +96,30 @@ def public_recipes_paginated(page, items_per_page=20): ) # noqa: E712 return recipes + def get_filtered_paginated_public_recipes(page=1, filters={}, items_per_page=30): + recipes_query = ( + db.session.query(Recipe) + .join(Recipe.reactions, isouter=True) + .filter( + or_( + UserRecipeReactions.user_id == current_user.id, + UserRecipeReactions.id == None, + ) # noqa: E712 + ) + .filter(Recipe.is_shared == True) + ) + if "ratio_from" in filters and filters["ratio_from"]: + recipes_query = recipes_query.filter(Recipe.ratio >= filters["ratio_from"]) + if "ratio_to" in filters and filters["ratio_to"]: + recipes_query = recipes_query.filter(Recipe.ratio <= filters["ratio_to"]) + if "with_reaction" in filters and filters["with_reaction"] is True: + recipes_query = recipes_query.filter( + UserRecipeReactions.user_id == current_user.id + and UserRecipeReactions.recipe_id == Recipe.id + ) + + return recipes_query.all() + def create_and_save(self, ingredients): db.session.add(self) db.session.flush() diff --git a/app/templates/cookbook/index.html.j2 b/app/templates/cookbook/index.html.j2 index 2fe3b991..bfc4eb27 100644 --- a/app/templates/cookbook/index.html.j2 +++ b/app/templates/cookbook/index.html.j2 @@ -16,7 +16,7 @@ {% block content %}
-
+ {{ form.csrf_token }} {% from "macros/_form_element.html.j2" import render_field %}
From 49f1762bb396d455a4d195d99eaeb89da1ee72a9 Mon Sep 17 00:00:00 2001 From: Jan Peterka Date: Mon, 9 Nov 2020 22:46:19 +0100 Subject: [PATCH 6/6] Add filter by ingredient --- app/controllers/cookbook.py | 4 +++- app/models/recipes.py | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/controllers/cookbook.py b/app/controllers/cookbook.py index 4f50c07f..ef1a0333 100644 --- a/app/controllers/cookbook.py +++ b/app/controllers/cookbook.py @@ -40,17 +40,19 @@ def before_index(self): # page = request.args.get("page", 1, type=int) # self.recipe_pagination = Recipe.public_recipes_paginated(page, 30) # self.recipes = self.recipe_pagination.items + self.all_recipes = Recipe.public_recipes() self.recipes = Recipe.get_filtered_paginated_public_recipes( 1, filters={ "ratio_from": ratio_from, "ratio_to": ratio_to, "with_reaction": with_reaction, + "ingredient_name": ingredient_name, }, ) # Get values for filters - ingredients = [x.ingredients for x in self.recipes] + ingredients = [x.ingredients for x in self.all_recipes] flatten_ingredients = [y for x in ingredients for y in x] ingredient_names = [x.name for x in flatten_ingredients] self.ingredient_names = ["--všechny--"] diff --git a/app/models/recipes.py b/app/models/recipes.py index 77cdc200..a47873a4 100644 --- a/app/models/recipes.py +++ b/app/models/recipes.py @@ -117,6 +117,14 @@ def get_filtered_paginated_public_recipes(page=1, filters={}, items_per_page=30) UserRecipeReactions.user_id == current_user.id and UserRecipeReactions.recipe_id == Recipe.id ) + if "ingredient_name" in filters and filters["ingredient_name"]: + recipes_query = ( + recipes_query.join(RecipeHasIngredients) + .join(Ingredient) + .filter(Ingredient.name == filters["ingredient_name"]) + ) + + print(recipes_query) return recipes_query.all()