I'm new to Django and I have a problem I can't seem to solve. Long story short, I created a text based app that helps me create a meal plan and generates a shopping list. And I'm trying to recreated with django.
Here are my models:
class Recipe(models.Model):
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(max_length=20)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.name
class IngredientSet(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.SET_NULL, null=True)
ingredient = models.ForeignKey(Ingredient, on_delete=models.DO_NOTHING)
quantity = models.FloatField()
def __str__(self):
return self.ingredient.name
Now, on my List Views I want to display the names of stored recipes as links. Each recipe link should call a Detail View which will display selected recipe's sets of ingredients. I can't figure out how to access those by their foreign key(which points to a recipe).
One can access reverse relations by using the model name in lowercase with _set
appended. For Recipe
and IngredientSet
you can write recipe.ingredientset_set.all()
to get all the instances of IngredientSet
related to a recipe. One can customize this name by setting the related_name
eg:
class IngredientSet(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.SET_NULL, null=True, related_name="ingredient_sets")
ingredient = models.ForeignKey(Ingredient, on_delete=models.DO_NOTHING)
quantity = models.FloatField()
def __str__(self):
return self.ingredient.name
Now you can write recipe.ingredient_sets.all()
.
To loop over this in the template one can simply write:
{% for ingredient_set in recipe.ingredient_sets.all %}
{{ ingredient_set.ingredient.name }}
{{ ingredient_set.quantity }}
{% endfor %}
Note : This will make a query to the database for each recipe to get it's ingredient set. You can use
prefetch_related
[Django docs] if you want to reduce the amount of queries made.
assuming that you want to display the names of stored recipes in a html template as links:
from .models import Recipe, Ingredient, IngredientSet
from django.shortcuts import render
def recipes(request):
recipes_for_template = Recipe.objects.all()
return render(request, 'main/recipes.html', {"recipes": recipes_for_template})
def ingredients(request, cod_recipe):
ingredients_sets = IngredientSet.objects.filter(recipe=cod_recipe)
ingredients_to_template = []
for ingredient_set in ingredients_sets:
ingredient_obj = Ingredient.objects.get(id=ingredient_set.id)
dict_of_ingredient = {
"name": ingredient_obj.name,
"quantity": ingredient_set.quantity
}
ingredients_to_template.append(dict_of_ingredient)
return render(request, 'main/ingredients.html', {"ingredients": ingredients_to_template})
where main is the name of the app
<table>
<thead>
<th>Recipe</th>
</thead>
<tbody>
{% for recipe in recipes %}
<tr>
<td>
<a href="./{{recipe.id}}/">{{recipe.id}}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% for ingredient in ingredients %}
{{ingredient.name}}
{{ingredient.quantity}}
{% endfor %}
from django.urls import path
from . import views
app_name = "main"
urlpatterns = [
path('recipe/', views.recipes, name='recipes'),
path('recipe/<int:cod_recipe>/', views.ingredients, name='ingredients'),
]
I think this is it, any doubts i will be glad to answer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.