From 0ab4c37785c8646eedb4875cdf0d8a86107ef264 Mon Sep 17 00:00:00 2001 From: lucas Date: Fri, 29 Apr 2022 17:11:38 -0700 Subject: [PATCH] Improved delete, scaling added --- main.py | 39 ++++---- recipe.py | 203 ++++++++++++++++++++++------------------- recipes/recipes.json | 23 ++++- templates/base.html | 4 + templates/new.html | 45 ++++++--- templates/recipe.html | 19 ++-- templates/recipes.html | 3 +- 7 files changed, 202 insertions(+), 134 deletions(-) diff --git a/main.py b/main.py index b6ed339..004b1e5 100644 --- a/main.py +++ b/main.py @@ -4,9 +4,7 @@ Written by Lucas Jensen Last updated 3/29/22 for Assignment 1 """ from flask import Flask, redirect, render_template, request -from markupsafe import escape - -from recipe import Recipe, RecipeBook, open_json +from recipe import Recipe, RecipeBook app = Flask(__name__) @@ -17,39 +15,42 @@ def home(): @app.route('/recipes', methods=['GET']) -def ReturnJSON(): - recipes = open_json() +def recipes_page(): + recipes = book.get_recipes() + # recipes is a dictionary of recipe objects if recipes == {}: return render_template("empty.html") return render_template("recipes.html", content=recipes) -@app.route('/recipes/<_id>', methods=['GET']) +@app.route('/recipes/<_id>', methods=['GET', 'POST']) def recipe_page(_id): - if request.method == 'GET': - recipe = book.find_by_id(_id) + recipe = book.find_by_id(_id) - return render_template("recipe.html", content=recipe, _id=_id) + if request.method == 'POST': + scale = request.form.get('scale') + new = recipe.scale(scale) + new_id = book.add_recipe(new) + return redirect(f'/recipes/{new_id}') + + return render_template("recipe.html", content=recipe, _id=_id) @app.route('/recipes/<_id>/delete') def delete_recipe(_id): - book.delete(_id) - + book.find_and_delete(_id) return redirect("/recipes") @app.route('/add', methods=['GET', 'POST']) def add_recipe(): if request.method == "POST": - flour = request.form.get("flour_weight") - water = request.form.get("water_weight") - salt = request.form.get("salt_weight") - loaves = request.form.get("yield") - name = request.form.get("name") + new_recipe = Recipe(request.form.get('name'), request.form.get('yield')) + for item in request.form: + if item not in ['name', 'yield']: + new_recipe.add_ingredient(item, int(request.form.get(item))) - new_recipe = Recipe(name, loaves, flour, water, salt) - book.add_recipes(new_recipe) + book.add_recipe(new_recipe) return redirect("/recipes") return render_template("new.html") @@ -57,4 +58,4 @@ def add_recipe(): if __name__ == "__main__": book = RecipeBook() - app.run(debug=True) + app.run(debug=False) diff --git a/recipe.py b/recipe.py index b0f6a83..531f4f8 100644 --- a/recipe.py +++ b/recipe.py @@ -3,7 +3,11 @@ Written by Lucas Jensen Portfolio Project for CS361 The main logic behind a recipe """ + import json +from pprint import pprint + +JSON_FILE = "recipes/recipes.json" class RecipeBook: @@ -11,38 +15,29 @@ class RecipeBook: Represents a recipe book containing several bread recipes """ def __init__(self): - self._recipes = self.__build_recipes() + self._recipes = {} # a dictionary of recipe objects, ID as key + self._id = 0 + self.__build_recipes() - @staticmethod - def __build_recipes(): + def __build_recipes(self): """ Builds the recipe book from an existing json file + :return: """ - with open("recipes/recipes.json", "rt") as f: - recipes = json.load(f) + with open(JSON_FILE, 'rt') as f: + recipes_dict = json.load(f) - return recipes + for _id in recipes_dict: + recipe_dict = recipes_dict[_id] + recipe = Recipe(recipe_dict['name'], recipe_dict['quantity']) + recipe.set_id(_id) + ingredients = recipe_dict['ingredients'] + for ingredient in ingredients: + recipe.add_ingredient(ingredient, ingredients[ingredient]) + recipe.add_ingredient(ingredient, ingredients[ingredient]) + self._recipes[_id] = recipe - def add_recipes(self, recipe: object) -> None: - """ - Adds a recipe to the book - :param recipe: bread recipe object - :return: nothing - """ - keys = open_json() - count = 0 - - while str(count) in keys: - count += 1 - - self._recipes[count] = recipe - self.save(count, recipe) - - def get_recipes(self) -> list: - """ - get the dict of recipes - :return: the dict of recipes - """ + def get_recipes(self): return self._recipes def find_by_id(self, _id: int) -> object: @@ -51,58 +46,83 @@ class RecipeBook: :param _id: int, the id of the recipe :return: recipe object """ - return self._recipes[_id] + return self._recipes[str(_id)] - def save(self, _id: int, recipe: object) -> None: + def find_and_delete(self, _id): """ - Saves a recipe to the JSON file - :param _id: int - :return: nothing - """ - self._recipes[_id] = recipe.get_recipe() - - with open("recipes/recipes.json", "wt") as f: - json.dump(self._recipes, f, indent=4) - - def delete(self, _id: int) -> None: - """ - Deletes a recipes as found by its ID - :param _id: int: id of the recipe + Finds a recipe using its ID and deletes it + :param _id: int of the recipe's ID :return: nothing """ del self._recipes[str(_id)] - with open("recipes/recipes.json", "wt") as f: - json.dump(self._recipes, f, indent=4) + # remove from JSON file + with open(JSON_FILE, 'rt') as f: + json_file = json.load(f) + + pprint(json_file) + + del json_file[str(_id)] + + with open(JSON_FILE, 'wt') as f: + json.dump(json_file, f, indent=4) + + def add_recipe(self, recipe): + """ + appends a recipe object to the recipe book + :param recipe: recipe object + :return: the id of the newly stored recipe + """ + with open(JSON_FILE, 'rt') as f: + keys = json.load(f) + + while str(self._id) in keys: + self._id += 1 + + recipe.set_id(self._id) + saved_id = self._id + self._recipes[str(self._id)] = recipe + self._id += 1 + # pprint(self._recipes) + self.save(recipe) + + return saved_id + + @staticmethod + def save(recipe): + """ + appends a recipe dictionary to the JSON file + :param recipe: + :return: + """ + with open(JSON_FILE, 'rt') as f: + recipe_dict = json.load(f) + + recipe_dict[recipe.get_id()] = recipe.get_recipe() + + with open(JSON_FILE, 'wt') as f: + json.dump(recipe_dict, f, indent=4) class Recipe: """ Represents a bread recipe """ - def __init__(self, name, num_loaves, ap_flour, water, salt): + def __init__(self, name: str, num_loaves: int): self._name = name self._num_loaves = num_loaves - self._ingredients = { - 'ap_flour': ap_flour, - 'water': water, - 'salt': salt - } - - def get_name(self) -> str: - """ - Gets the name of a recipe - :return: - """ - return self._name + self._ingredients = {} + self._id = None def get_recipe(self) -> dict: """ - :return: returns the whole recipe as a dict, including quantity + builds and returns the whole recipe as a single dictionary + :return: dictionary """ recipe_dict = { 'quantity': self._num_loaves, 'name': self._name, + # 'id': self._id, 'ingredients': {} } @@ -111,18 +131,21 @@ class Recipe: return recipe_dict + def get_name(self) -> str: + return self._name + def get_num_loaves(self) -> int: - """ - :return: int: number of loaves the recipe calls for - """ return self._num_loaves def get_ingredients(self) -> dict: - """ - :return: dictionary of all ingredients - """ return self._ingredients + def get_id(self) -> int: + return self._id + + def set_id(self, _id): + self._id = _id + def add_ingredient(self, name: str, mass: int) -> None: """ Adds an ingredient to the recipe. Mass in grams. @@ -132,54 +155,50 @@ class Recipe: """ self._ingredients[name] = mass - def scale(self, new_num: int) -> object: + def scale(self, new_num) -> object: """ Scales the recipe by a given factor :param new_num: integer, the number of desired loaves :return: Recipe object, now scaled """ - scale = new_num / self._num_loaves + scale = int(new_num) / int(self._num_loaves) - ap_flour = self._ingredients['ap_flour'] * scale - water = self._ingredients['water'] * scale - salt = self._ingredients['salt'] * scale - name = f"{self._name} * {scale}" - - scaled_recipe = Recipe(name, new_num, ap_flour, water, salt) + scaled_recipe = Recipe(f"{self._name} * {scale}", new_num) for ingredient in self._ingredients: - if ingredient not in ['ap_flour', 'water', 'salt']: - mass = self._ingredients[ingredient] * scale - scaled_recipe.add_ingredient(ingredient, mass) + mass = self._ingredients[ingredient] * scale + scaled_recipe.add_ingredient(ingredient, round(mass)) return scaled_recipe def default_recipes(): - recipe_1 = Recipe('Country Brown', 1, 600, 300, 13) - recipe_2 = Recipe('Conventional White', 2, 1000, 700, 25) + """Adds some sample data""" + recipe_1 = Recipe('Country Brown', 1) + recipe_2 = Recipe('Conventional White', 2) + + sample_recipes = [recipe_1, recipe_2] + flour = 500 + water = 300 + salt = 12 + + for recipe in sample_recipes: + recipe.add_ingredient("AP Flour", flour) + flour += 500 + recipe.add_ingredient("Water", water) + water += 300 + recipe.add_ingredient("salt", salt) + salt += 12 + recipe_3 = recipe_2.scale(4) - return [recipe_1, recipe_2, recipe_3] + sample_recipes.append(recipe_3) - -def open_json(): - """TODO""" - with open('recipes/recipes.json') as f: - data = json.load(f) - - return data + return sample_recipes if __name__ == "__main__": recipes = default_recipes() book = RecipeBook() for recipe in recipes: - book.add_recipes(recipe) - - # for recipe in book.get_recipes(): - # print(book.get_recipes()[recipe]) - # - # rec = Recipe('sandwich loaf', 2, 1000, 700, 25) - # rec.add_ingredient('ww flour', 500) - # rec.save('recipes.json') + book.add_recipe(recipe) diff --git a/recipes/recipes.json b/recipes/recipes.json index d739ed6..cfb3eb8 100644 --- a/recipes/recipes.json +++ b/recipes/recipes.json @@ -1,11 +1,26 @@ { - "0": { + "3": { "quantity": "2", "name": "Sourdough", "ingredients": { - "ap_flour": "1000", - "water": "600", - "salt": "20" + "AP Flour": 800, + "WW Flour": 200, + "Water": 700, + "Salt": 20, + "Yeast": 0, + "Starter": 50 + } + }, + "7": { + "quantity": "5", + "name": "Sourdough * 2.5", + "ingredients": { + "AP Flour": 2000, + "WW Flour": 500, + "Water": 1750, + "Salt": 50, + "Yeast": 0, + "Starter": 125 } } } \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 3f2120d..e917433 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,6 +1,7 @@ + @@ -26,4 +27,7 @@ © Copyright 2022 by Lucas Jensen. {% endblock %} + + + \ No newline at end of file diff --git a/templates/new.html b/templates/new.html index 87eb783..1c1474d 100644 --- a/templates/new.html +++ b/templates/new.html @@ -7,23 +7,44 @@ {% block content %} -

New Recipe

+

New Recipe

-
- -
-

Enter all values grams.

+ + + + + + + +
+ + + +
+ + + +
-{% for ing in ['flour', 'water', 'salt'] %} -
-
-
-{% endfor %} +

Enter all values grams. If an ingredient is not needed, input 0.

-
- + + + + + + + {% for item in ['AP Flour', 'WW Flour', 'Rye Flour', 'Water', 'Salt', 'Yeast', 'Starter'] %} + + + + + + + {% endfor %} +
IngredientMass in g
diff --git a/templates/recipe.html b/templates/recipe.html index 95e11fc..05cf228 100644 --- a/templates/recipe.html +++ b/templates/recipe.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% block title %}{{content["name"]}}{% endblock %} +{% block title %}{{content.get_name()}}{% endblock %} {% block html_head %} @@ -7,24 +7,31 @@ {% block content %} -

{{content["name"]}} Recipe

+

{{ content.get_name() }} Recipe

-

Number of loaves: {{content['quantity']}}

+

Number of loaves: {{ content.get_num_loaves() }}

- {% for item in content['ingredients'] %} + {% for item in content.get_ingredients() %} - - + + {% endfor %}
Ingredient Grams
{{ item.title() }}{{ content['ingredients'][item] }}{{ item }}{{ content.get_ingredients()[item] }}
+

Scaling

+ + + + +
+ diff --git a/templates/recipes.html b/templates/recipes.html index e94cb5b..2ded92e 100644 --- a/templates/recipes.html +++ b/templates/recipes.html @@ -11,7 +11,8 @@