I'm working on my first Django project (the final project for codecademy's Django class) and I'm making webpages to show the inventory and menu that a restaurant has. I made the model, view, template, etc. for inventory and it displays the ListView perfectly. I did the same thing for my menu and it doesn't work. The page loads but the table that's supposed to output data is empty.
Any insight on what might be going wrong?
PS I'm new to programming and this is my first stackoverflow post so forgive any formatting errors or other faux pas
## views.py
from django.http import HttpResponse
from django.shortcuts import render
from .models import Inventory, MenuItem, RecipeRequirement, Purchase
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.views.generic import ListView
# Create your views here.
def index(request):
return render(request, "index.html")
class InventoryList(ListView):
template_name = "inventory.html"
model = Inventory
class MenuList(ListView):
template_name = "menu.html"
model = MenuItem
Inventory (below) works fine! :)
{% extends './base.html' %}
{% block content %}
<h2>Inventory</h2>
<table id="inventory">
<tr>
<th>Ingredient</th>
<th>Price</th>
<th>Units Available</th>
</tr>
{% for ingredient in inventory_list %}
<tr>
<tr>
<td>{{ ingredient.ingredient_name }}</td>
<td>{{ ingredient.price }}</td>
<td>{{ ingredient.units_avail }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
This one (Menu) is the problematic one :(
{% extends './base.html' %}
{% block content %}
<h2>Menu</h2>
<table id="menu">
<tr>
<th>Item</th>
<th>Price</th>
<th>In Stock?</th>
</tr>
{% for food in menu_list %}
<tr>
<tr>
<td>{{ food.menu_item_name }}</td>
<td>{{ food.price }}</td>
<td>{{ food.available }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Models below
from django.db import models
from django.forms import DateTimeField
# Create your models here.
class Inventory(models.Model):
ingredient_name = models.CharField(max_length=30)
price = models.DecimalField(max_digits=5, decimal_places=2)
units_avail = models.IntegerField()
def __str__(self):
return self.ingredient_name " avail: " str(self.units_avail)
class MenuItem(models.Model):
menu_item_name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return self.menu_item_name " with Price: " str(self.price)
def available(self):
return all(recipe_req.enough() for recipe_req in self.reciperequirement_set.all())
class RecipeRequirement(models.Model):
ingredient = models.ForeignKey(Inventory, on_delete=models.CASCADE)
menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
quantity = models.IntegerField()
def __str__(self):
return self.ingredient.ingredient_name " in " self.menu_item.menu_item_name
def enough(self):
return self.quantity <= self.ingredient.units_avail
class Purchase(models.Model):
menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
timestamp = models.DateTimeField()
def __str__(self):
return self.menu_item.menu_item_name " at " self.timestamp
URLs below
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("inventory", views.InventoryList.as_view(), name="inventory_list"),
path("menu", views.MenuList.as_view(), name="menu_list"),
]
CodePudding user response:
I notice that the RecipeRequirement
model Class has the method available
. This method calls the method enough
from the RecipeRequirement
model Class.
One troubleshooting strategy is to disable (comment out) the methods enough
and available
as they are introducing logic that would prevent display of menu items. In other words, your code appears to read: If we don't have enough ingredients there is no point returning menu items for recipes that we cannot make.
An alternative troubleshooting strategy is to populate the RecipeRequirement
table with sufficient ingredients and it should work. Caveat: This answer is untested.
Here's a tip for a newcomer to coding that has served me well in my brief journey into software development. Errors have been my greatest teacher. When there are errors try to reduce as many elements as you can. When you hit a wall like this consider what is essential and comment out the rest. I suggested commenting out the two methods first because they are not required for the tables to display (or for what you report as being central to your question). Once you get the menu items displaying then you can re-introduce those methods one at time.
CodePudding user response:
I could see one problem, you have one extra <tr>
tag open in both the templates just below the loop.
Also think some problem with available
method you manually defined in MenuItem
model, so I removed it, try without it.
Also I'd recommend you to use context_object_name
which is by default object_list
so:
class InventoryList(ListView):
template_name = "inventory.html"
model = Inventory
context_object_name="inventories"
class MenuList(ListView):
template_name = "menu.html"
model = MenuItem
context_object_name="menu_list"
inventory.html template:
{% extends './base.html' %}
{% block content %}
<h2>Inventory</h2>
<table id="inventory">
<tr>
<th>Ingredient</th>
<th>Price</th>
<th>Units Available</th>
</tr>
{% for ingredient in inventories %}
<tr>
<td>{{ ingredient.ingredient_name }}</td>
<td>{{ ingredient.price }}</td>
<td>{{ ingredient.units_avail }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
menu.html template:
{% extends './base.html' %}
{% block content %}
<h2>Menu</h2>
<table id="menu">
<tr>
<th>Item</th>
<th>Price</th>
<th>In Stock?</th>
</tr>
{% for food in menu_list %}
<tr>
<tr>
<td>{{ food.menu_item_name }}</td>
<td>{{ food.price }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Note: It's recommended to give
/
at the end of every route so your urls.py should be:
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("inventory/", views.InventoryList.as_view(), name="inventory_list"),
path("menu/", views.MenuList.as_view(), name="menu_list"),
]
Note: class based views in Django requires their name to be written as model name as prefix and actual view name as suffix, so you may change it to
InventoryListView
andMenuItemListView
fromandInventoryList
respectively.MenuList