class IndexView(generic.ListView):
context_object_name = 'recipes_list'
def get_queryset(self):
return Recipe.objects.all()
def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
recipe['steps'] = Steps.objects.filter(recipe_id=pk)
template = loader.get_template('recipe/recipe_detail.html')
context = {
'recipe': recipe,
}
return HttpResponse(template.render(context, request))
def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
steps = Steps.objects.filter(recipe_id=pk)
template = loader.get_template('recipe/recipe_detail.html')
context = {
'recipe': recipe,
'steps': steps
}
return HttpResponse(template.render(context, request))
def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
steps = Step.objects.filter(recipe_id=pk)
ingredients = dict()
for step in steps:
ingredients[step.id] = StepIngredients.objects.filter(step_id=step.id)
template = loader.get_template('recipe/rezept_detail.html')
context = {
'recipe': recipe,
'steps': steps,
'ingredients': ingredients
}
return HttpResponse(template.render(context, request))
<h1>{{ recipe.name }}</h1>
<table>
{% for step in steps %}
<tr>
<td>
{% for ingredient in ingredients.step.id %}
{{ ingredient.amount }}
{% endfor %}
</td>
<td>{{ step.description }}</td>
</tr>
{% endfor %}
</table>
Dear Django Community,
as a first django project I tried to write a site to manage cooking recipes. My model is quite simple:
* 1 recipe has n steps
* 1 step has a description and n ingredients, each of a certain amount defined by a certain unit
all in all, I have 5 tables (Recipe, Step, Ingredient, Unit, StepIngredient).
After reading through some documentation and trying around a little bit, I got my model and my admin site (I had to install django-nested-inline for the admin site to fit my expectations).
Now I am struggeling with my views. There is a simple index view wich basically lists all recipes:
class IndexView(generic.ListView):
context_object_name = 'recipes_list'
def get_queryset(self):
return Recipe.objects.all()
The hard part is setting up the details view. It is supposed to show the recipes name as a title and then list all the required ingredients and all the required steps. It tried something like:
def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
recipe['steps'] = Steps.objects.filter(recipe_id=pk)
template = loader.get_template('recipe/recipe_detail.html')
context = {
'recipe': recipe,
}
return HttpResponse(template.render(context, request))
but it seems I am not allowed to modify the recipes object. Any ideas how to pass all the data which belongs to recipe to the template?
You could do something like this:
def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
steps = Steps.objects.filter(recipe_id=pk)
template = loader.get_template('recipe/recipe_detail.html')
context = {
'recipe': recipe,
'steps': steps
}
return HttpResponse(template.render(context, request))
And make appropriate changes to your template.
Thank you Rahul,
I actually tried that an this is possible for the relationship between a recipe and its steps. But when it comes to the ingredients for a single step, I cannot do this any more since the ingredients depend on steps again. After reading your suggestion I thought about it once more and I came up with the following solution:
def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
steps = Step.objects.filter(recipe_id=pk)
ingredients = dict()
for step in steps:
ingredients[step.id] = StepIngredients.objects.filter(step_id=step.id)
template = loader.get_template('recipe/rezept_detail.html')
context = {
'recipe': recipe,
'steps': steps,
'ingredients': ingredients
}
return HttpResponse(template.render(context, request))
However, when it comes to the view, it does not work any more:
<h1>{{ recipe.name }}</h1>
<table>
{% for step in steps %}
<tr>
<td>
{% for ingredient in ingredients.step.id %}
{{ ingredient.amount }}
{% endfor %}
</td>
<td>{{ step.description }}</td>
</tr>
{% endfor %}
</table>
According to what I found on google, the django template language cannot deal with accessing dictionary entries using variables as keys. What is the django-way of solving this problem? Any ideas?
class Recipe(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
class Step(models.Model):
step_number = models.IntegerField()
description = models.TextField()
recipe = models.ForeignKey(Recipe)
recipe = Recipe.objects.get(id=1)
recipe.steps
recipe.step_set
I might be wrong here, but this is what I understand:
Let's say you have something like this:
class Recipe(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
class Step(models.Model):
step_number = models.IntegerField()
description = models.TextField()
recipe = models.ForeignKey(Recipe)now, if I do the following in the shell:
recipe = Recipe.objects.get(id=1)
recipe.stepswouldn't this give an error?
To get the step, I could do something like
recipe.step_setbut I don't think I'll be able to do recipe.steps
from __future__ import unicode_literals
from django.db import models
class Unit(models.Model):
abbreveation = models.CharField(max_length=5, primary_key=True)
description = models.CharField(max_length=50)
def __str__(self):
return "%s (%s)" % (self.description, self.abbreveation)
class Ingredient(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Step(models.Model):
name = models.CharField(max_length=255, blank=True)
recipe = models.ForeignKey('Recipe', related_name='steps', on_delete=models.CASCADE, null=True)
description = models.TextField()
ingredient = models.ManyToManyField(Ingredient, through='StepIngredient')
def __str__(self):
if (self.name == ''):
return "Step %d" % self.id
else:
return "Step %d (%s)" % (self.id, self.name)
# additional information for many to many relationship between schritt and zutat
class StepIngredient(models.Model):
class Meta:
unique_together = (('step', 'ingredient'),)
step = models.ForeignKey(Step, null=True)
ingredient = models.ForeignKey(Ingredient, null=True)
amount = models.DecimalField(max_digits=7, decimal_places=3)
unit = models.ForeignKey(Unit, null=True)
def __str__(self):
return "%d %s %s" % (self.amount, self.unit.abbreveation, self.ingredient)
class Recipe(models.Model):
name = models.CharField(max_length=255)
# file will be uploaded to MEDIA_ROOT/images
# TODO: Upload works but link fails. Maybe sth. wrong with MEDIA_URL???
photo = models.ImageField(upload_to='images/', null=True)
portionen = models.IntegerField(default=2)
def __str__(self):
return self.name
{% for step in recipe.steps.all %}
> Thank you James for pointing me at how to do my queries with django; I can finally list my steps using:
>
> {% for step in recipe.steps.all %}
>
> within my template. However, given the model above I am still not sure how to access a single steps ingredients ... any ideas or suggestions on my current model?
Sure, just have another nested {% for ingredient in step.ingredients.all %}
You should also change the 'ingredient' field to 'ingredients' in your Step model (reflected in my loop above). Makes it easier to read and indicate that you'll need the .all in the template (or elsewhere) if the attribute name is plural. Otherwise you are querying using step.ingredient, and expecting a list of multiple ingredients back.
-James
Thank you Florian. After James pointed out that I can access my steps (and the ingredients in some way) by just passing the recipe object to the templates context, I thought of reducing the view to a DetailView again. But I have to somehow access the ingredients from my template for now ...
class Part(models.Model):
parts = models.ForeignKey('Part', null=True, blank=True, default=None, related_name='pieces')
name = models.CharField(max_length=200)
class PartsView(generic.ListView):
context_object_name='parts'
model=Part
<h1>Parts</h1>
<ul>
{% for part in parts %}
<li></li>
{% endfor %}
</ul>
Inspired by Mike Dewhirsts suggestion on building hierachical structures,
I've made up another model:
class Part(models.Model):
parts = models.ForeignKey('Part', null=True, blank=True, default=None, related_name='pieces')
name = models.CharField(max_length=200)
Then I made my view:
class PartsView(generic.ListView):
context_object_name='parts'
model=Part
But how should I design my template now?
<h1>Parts</h1>
<ul>
{% for part in parts %}
<li></li>
{% endfor %}
</ul>
{% for item in assembly.qs %}
{% for item in assembly.qs %}
@Mike: the attempts (at least the ones I have seen) to store hierarchical data in relations [1] don't seem very intuitive to me. At least when it comes to query the data. Anyway: I would appreciate to be convinced by something else. However, I am afraid to kick off a completely different (yet interesting) discussion here. My current issue is how to access the additional fields of my M2M relationship. In addition to that I will think about hierarchical data in relational databases ;-)