Cannot see foreign key values in the template

This is my 2nd week learning Django. I'm trying to get comfortable with Django Template Language. I'm trying to make an Inventory app with 4 models. The views for them are class-based.

The templates for Ingredient and Menu work as expected. However, I'm struggling with trying to loop through values from the Purchase model which has a foreign key field 'menu_item'. The template is not showing anything from the for loop. I've referred numerous articles here to find most of them use function-based views. I've tried using {% for purchase in purchase_set %}, {% for purchase in purchase_set.all %}. I know the object to iterate over is a query-set. I cannot figure out what to do?

MODELS.PY

from django.db import models
# Create your models here.
class Ingredient(models.Model):
    Pounds = 'lbs'
    Ounces = 'oz'
    Grams = 'gms'
    Eggs = 'eggs'
    Piece = 'piece'
    Litre = 'litre'
    unit_choices = [(Pounds, 'lbs'),
                    (Ounces, 'ounces'),
                    (Grams, 'grams'),
                    (Eggs, 'eggs'),
                    (Piece, 'piece'),
                    (Litre, 'litre')]
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)
    unit_price = models.FloatField(default=0.0)
    quantity = models.FloatField(default=0.0)
    unit = models.CharField(max_length=10, choices=unit_choices)
    class Meta:
        ordering = ['id']

    def __str__(self):
        return self.name
class MenuItem(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50)
    price = models.FloatField(default=0.0)
    class Meta:
        ordering = ['id']
    def __str__(self):
        return self.title
class RecipeRequirement(models.Model):
    menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    quantity = models.FloatField(default=0.0)

    def __str__(self):
        return self.menu_item.title

class Purchase(models.Model):
    menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
    timestamp = models.DateTimeField()
    id = models.AutoField(primary_key=True)

    class Meta:
        ordering = ['id']
    def __str__(self):
        return self.menu_item.title

VIEWS.PY:

from django.shortcuts import render
from .models import Ingredient, MenuItem, RecipeRequirement, Purchase
from django.views.generic import ListView

def home(request):
    return render(request, 'inventory/home.html')

class IngredientView(ListView):
    model = Ingredient
    template_name = 'inventory/ingredients.html'

class PurchaseView(ListView):
    model = Purchase
    template_name = 'inventory/purchases.html'

class MenuView(ListView):
    model = MenuItem
    template_name = 'inventory/menu.html'

PURCHASES.HTML

<h3>This is purchases page.</h3>
{% block content %}
<table>
{% for purchase in purchase_set.all %}
        <tr>
            <td>{{ purchase.title }}</td>
        </tr>
{% endfor %}
</table>
{% endblock %}

The title field you are trying to show is in MenuItem model that is used as foreignkey in Purchase model with menu_item field. ListView class returns to context yours purchases in object_list key. So in Your purchases.html template:

<h3>This is purchases page.</h3>
{% block content %}
<table>
{% for purchase in object_list %}
        <tr>
            <td>{{ purchase.menu_item.title }}</td>
        </tr>
{% endfor %}
</table>
{% endblock %}

PS. This `purchase_set' is referring to reverse relationship. So if you would want to show all purchases of MenuItem you would do:

{% for item in menuitems %}
  <h1>{{ item }}</h1>
   {% for purchase in item.purchase_set.all %}
      <p>{{ purchase.timestamp }}</p>
   {% endfor %}
{% endfor %}
Back to Top