cproctor / cookbook

A simple command line tool for planning, shopping, and cooking

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add basic UI

cproctor opened this issue · comments

commented

Running into trouble when I try to make links... Everything else works ok, surprisingly enough.
Frankly this has mostly been me chopping up code from my tutorial project and changing variable names until it works... :D guess that's the fastest way to figure out what everything does.
Can you please let me know why the links in the index template files aren't working? I'll commit what I'm trying out... Thanks!

Update: The links work, it was a naming issue, yay! I just can't link across template directories... Can I have some help with that please? Also it won't let me commit updates to the template HTML files.

commented

Congrats! I think 2/3 of programming is "chopping up code from my tutorial project" so you're in good company.

I just committed a bunch of files with working examples of templates linking across directories--I hope it doesn't mess things up. I know you already have templates in place. It might be easiest to just stash your changes (git stash), pull this latest commit, and then pop your changes back on top (git stash pop). If all else fails, you could re-clone the repo somewhere else and then add your changes in manually.

I'm not sure why there should be any trouble committing template files... are you using the GitHub GUI or working from the command line?

Hahaha!!! Yay! What happened with the templates was that I just hadn't added them as things that should be staged for commits. Here's the UI!
Also, what does "base" do? Is it just built into Django?

commented

That's great! There's no magic in base--it's just the base template at cookbooks/templates/cookbooks/base.html. Have a look; it lays out the basic html tags like <head> and <body>. They also leave placeholders in the form of {% block whatever %}. Later templates inherit from base and redefine those blocks. Jinja's documentation has a nice explanation of template inheritance.

commented

The menu page looks much better with links to the menus. But clicking the links doesn't work for me (on FireFox, Chrome, or Safari). Do the links work for you? I think the issue is buttons aren't really designed to work as links. They're meant to be part of forms that submit some information to a server. What about just using regular <a href="">link</a> tags without the buttons?

Here's the next piece of trickiness: when you click on a recipe from a menu, you'd expect to see the recipe scaled up as appropriate for the menu. How could we support this? There are a few steps; none are too hard but putting them all together might be a bit tricky:

  • Need to add a new route that lets us view a recipe as part of a menu, something like cookbook/menus/<int:menuID>/recipes/<int:recipeID>
  • We need to add a new view, maybe called MenuRecipeDetailView.
  • We need to use the Menu and Recipe models to make this happen. I see two options here:
    • You could do the scaling-up math in the view, multiplying the amount needed of the ingredient by the recipe scaling factor. I'm already doing this math in Menu.shopping_list and Menu.cooking_view. I don't love this solution. Writing all that code every time you want to get a recipe as part of a menu seems like a pain (and we'll undoubtedly make mistakes that turn into bugs).
    • Instead, maybe we could add some method to the models that would do this for us. Then we just have to get it right once, and we'll use that method everywhere we need it. Where would be the best place to add this? How should it be implemented?

Do you think you can start on any parts of this? Are there parts you'd like me to help with?

commented

Having access to the menu and the recipe in the view will also let us make the presentation nicer--for example, we can add a link back to the menu

  1. The buttons work for me... I'll change it to links, though.
  2. I actually already started to work on making the recipes as a subset of the menus, but I didn't really know how to go about using the functions in the recipes and menus model files... so I've kind of just been messing around. But I can try to make a new method to scale it up. Since MenuRecipeDetailView would be under the menus templates section, I'm guessing that I should use the menus model file...
    I'll give it a shot.
  3. I'll add "go back" buttons on the pages to connect the pages both ways.
commented

Sounds good! Let me know if you get stuck. I'd suggest working from the outside in (the order I listed)... first, just getting the route working, then actually finding the right menu and recipe in the View, then doing the scaling stuff :)

I'm having a couple problems.

  1. I tried messing around with putting images in the base template (creative commons marked for reuse and/or redistribution, don't worry), but the images aren't showing up in the header. I don't know that much about the path for images...
  2. Django is giving me an error when I try to input 2 ids into the url (i.e. cookbook/menus/1/recipes/2). I'm not entirely sure how to resolve this...
  3. Since I'm stuck on most other things, I'm working on the model method, and testing it by calling it in a page template that I know I can get to (menu detail page right now, since the links for MenuRecipeDetail aren't working). I've chopped up shopping_list and cooking_view for now. How do I use the template to call a model method that needs an argument?

Thank you!

commented

Hi Maya! These issues are great--you've worked on a thing, gotten stuck, and know exactly what you need help with. I made a branch of this repo called "chris" so that I can demonstrate some techniques, and let you implement them the way you want in the "master" branch. You can checkout branches and switch between them on your local codebase but I'd say don't bother with that for now. Just look at the code online--there's a little dropdown on the left when you're browsing code that lets you see different branches. Anyway, on to the issues:

  1. This is a great question. The settings file (cookbook/settings.py) has some important values for static stuff down at the bottom: STATICFILES_DIRS and STATIC_URL. Remember how Django knows to go check all the apps for page templates? Same with static files. When you're in development mode, running the server off your computer, all those files are made available at STATIC_URL which is currently set to /static/. I added cookbook/static/pasta.jpg, and if you were to check out the "chris" branch and start the server, you could see it at http://localhost:8000/static/pasta.jpg.

    • That said, you don't need to worry about the URL for static files. In templates, you can just use the static tag and it will locate the right URL for you. Here's the code I added to make it work.
    • Why so complicated? Because down the road, if you had a huge site (Django was originally invented by a newspaper), you would have many gigabytes of static files. You would want some servers to do the computation (running django), and others just serving static files. You can use different Django commands to collect all the static files, bundle them off, and ship them off to some other server. (For example, you can serve static files really cheaply on Amazon Web Services.) Then you'd just change the STATIC_URL variable and everything would still work!
  2. We need a few steps; you can see all the changes in this commit diff.

    • In cookbook/urls.py we need to add a route that matches this URL, with a placeholder for two primary keys. Here's the change I made.
    • I pointed that URL to a view which doesn't exist, MenuRecipeDetailView. So we need to add that to menus/views.py. The nice thing about class-based views is that they do all the work for you and you can override any parts you need to customize. This makes them hard to learn about though, since so much is happening that you can't see. (See learning note below.)
    • Getting the recipe is a two-step business. First, we need to get the menu, and then get the recipe from its recipes. If either fails, we return 404. There's a get_object method that the view already relies on to get the object. So I redefine that method to do what I just described. I also store the menu and the view as properties of the view (lines 21 and 22 of the commit diff).
    • I want to make the menu and the recipe available in the template, so I can show them, link to them, etc.There's another view method I can override: get_context_data (line 27. Any properties I add to context are available in the template. So I just attach menu and recipe. You can read more about adding extra context in the docs.
    • Finally, I need to actually write the template. It's almost the same as the regular recipe view, except for line 6 where I link back to the parent menu. Previously, this would be impossible.
  3. Generally, the view is responsible for getting what's needed from models, and making it available to the template. I'd encourage you to follow this pattern, adding what you need to the template context with get_context_data as above. (Templates do allow you to call model methods, but I don't think they allow you to call them with arguments. Maybe you can. But they don't want you to!) When you're debugging models, sometimes it's easier to use the interactive shell rather than the web browser. You can run python manage.py shell and it will drop you into a regular Python shell, with all the Django context loaded up. This allows you to do things like:

>>> from menus.models import Menu
>>> menu = Menu.objects.get(pk=1)
>>> menu.recipes.all()
<QuerySet [<Recipe: Grated Carrot and Beet Salad with Bulgur and Figs>, <Recipe: Vinegar slaw with cucumbers and dill>, <Recipe: White bean and garlic soup with greens>]>
>>> recipe = menu.recipes.first()
>>> recipe.ingredients.count() 
11

Now see if you can port these changes into the main branch, maybe without the pasta picture! Have fun, and keep the questions coming if you get stuck. I promise it'll keep speeding up--you'll be able to go longer without getting stuck and you'll get unstuck more quickly! It's everybody's path to learning this stuff. And there are really neat ideas around the corner that are so cool but you don't have the equipment yet to be able to think about them. You're building that equipment now.


Learning note: first, just figure out how to make them work, like we're doing now. Then, at some point, read the in-depth documentation on generic views. Remember how it was overwhelming before? At some point it won't be anymore because you'll know your way around a little more. Then you'll enjoy reading it. Until then don't! And finally, the day will come when you actually start reading the Django source code to understand what's happening. It's actually pretty easy to understand. But not yet!