With the AJAX proof of concept complete, it was time to turn my attention to a more complicated database model, one that would hopefully sustain me for the foreseeable future. Why would I need a more complex database model? Simply put, because the old system does not store enough data.
Let me explain. The old model, storing a grocery list and a set of lines linked to the list, works for a single recipe, but the whole point of the app is to consolidate recipes, and that’s where things quickly become more difficult. The fact that each line is stored as a string doesn’t give the opportunity to consolidate ingredients and encourages redundant lines. Additionally, although the parser is getting ingredients, it’s not doing anything with them except making those words a different color.
No, what I wanted was to be able to have a consolidated grocery list, and for that list to contain a number of cleaned up lines, with links to the original lines that they came from. I also wanted to be able to quickly sort the list by the different recipes, and make editing them easy and simple. For that, I was going to need a new set of models.
I came up with a four model system:
- A
RecipeList
model that stores entered recipes (like the originalGList
model) - A
RawLine
model that stores the string line and some of the parsed information (like the originalLine
model) - A
CleanedLine
model that stores a cleaned up version of the lines, separaitng amount, ingredient, and measurement - A
CompiledList
model that holds theCleanedLine
models, the same way theRecipeList
holds theRawLines
Here’s the code setting up the database:
Most of this is pretty straightforward. The trickiest part was figuring out all of the database relationships. SQL isn’t the easiest thing to debug, I’m discovering. But I feel the relationships are important because, in the creation of the grocery list, users are going to need to track down, say the origin of a CleanedLine
or get a list of all the recipes that a CompliedList
is made of. And while there are probably a few more models I’m going to want to add (for example, establish users), I’m hopeful that this 4-model system will sustain me for a while, and I won’t have to go mucking through SQLAlchemy for a while yet.
Integrating the new model into the app
Next, it was time to make use of the new model. Because I still wanted the user to have input on cleaning the recipe lines, I modified my previous list page to become a sort of “cleaning” landing page, changing the routes accordingly. Then I added a “submit” form on the bottom that would generate the new list and redirect the user. Validating this form would then start the logic to actually clean the lines, going off of the user-aided data as a guide.
Note the extract_ingredients
function. This is a helper function that I put in my utils.py
folder. It iterates through the JSON color data and extracts the ingredient, amount, and measurement, returning them:
The only issue I have with this is that it doesn’t support more than one ingredient on a line. That’s a special use case I’m going to have to come back to.
But this essentially establishes the basic workflow for creating a new list: a user enters a url, it’s parsed and they’re taken to a “cleaning” page. From there, they will have the option to edit/help along the spaCy ingredient parser before submitting annotated lines. The program then cleans them up and spits out a CompiledList
of CleanedLines
on the main list page.
In order to test that it was all working, I put together an html template to print the compiled list. And all appears to be working properly:
This was a difficult one; I’m still a bit shaky on databases and there were some errors that really had me tearing my hair out. It’s also starting to dawn on me that this is a bigger project, maybe much bigger, than I originally had planned. But hey, that’s part of the fun, right? The fact that it’s hard shows it’s worth doing.
Next steps:
- add more than one recipe to a single lists
- give the option to select lists on main page
- fix the cleaning page so that it actually cleans
…and much much more. Until next time, Steve signing out.