I try to display data from db and place them under correct title.
models.py
class Game(models.Model):
location= models.ForeignKey('location', on_delete=models.CASCADE')
group = models.IntegerField()
firstname = models.CharField()
surname = models.CharField()
views.py
class group(generic.CreateView):
template_name = 'group.html'
def get(self, request, *args, **kwargs):
game = Game.objects.filter(location__type__pk=kwargs['pk']).order_by('location__pk', 'group')
context = {
'game': game,
}
return render(request, self.template_name, context)
Lets say that the 'group' can be like A, B, C etc.
In the template I want to display it like
Location Foo
Group A
Jonas Andersson
Lisa Silverspoon
Group B
Sven Bohlin
Göran Lantz
Location Bar
Group A
Mia Milakovic
Lars Larsson
Group B
Anna Annasdotter
I have tried with so many variants of for-loops without any success.
Is it possible? Can you do this?
You can use template filter regroup, as in,
{% regroup games by location as games_list %}
{% for location, games in country_list %}
{{ location }}
{% for game in games %}
{{ game.group }}
...
{% endfor %}
{% endfor %}
Note: games here is a list, which is why you need to loop over it again.
Hope this helps!
The builtin regroup tag should enable you to do this, but you'll need to use it twice in order to achieve the nested grouping that you're looking for.
{% regroup game by location as games_loc %} <!-- Group by "location" -->
{% for location, l_games in games_loc %}
<div>{{ location }}</div>
{% regroup l_games by group as games_grp %} <!-- Group by "group" -->
{% for group, g_games in games_grp %}
<div>{{ group }}</div>
{% for g in g_games %} <!-- Display games in group -->
<div>{{ g }}</div>
{% endfor %}
{% endfor %}
{% endfor %}
Related
Hej! :)
I have a model to create single institutions (Institution) and can connect it to a parent institution, via parent_institution (self).
So I have the institution A, which is parent to b, c, d (All themselves single institutions with an own detail view.) In the detail view of b I have the section 'parent institution' where I get A as a result, including a link to the detail view of A.
<p><b>Parent institution: </b>
{% if institution.parent_institution %}
<a href="{% url 'stakeholders:institution_detail' institution.parent_institution.id %}">
{{institution.parent_institution}}
</a>
{% endif %}
</p>
Following this link I get to the detail view of A where I want a section with the child institutions. There should b, c, d be listed.
I added a related name to the parent_institution
class Institution(models.Model):
name = models.CharField(
verbose_name=_("Name of the institution"),
max_length=200,
)
parent_institution = models.ForeignKey(
"self",
verbose_name=_("Parent institution"),
on_delete=models.SET_NULL,
blank=True,
null=True,
help_text=_("if applicable"),
related_name="child",
)
normally I can follow the ForeignKey in the opposite direction via this related_name.
<p><b>Child institution: </b>
{{institution.child.name}}
</p>
but in this case this is not working and gives me 'None'. Therefor did I try:
{% if institution.id == institution.all.parent_institution.id %}
{{institution.name}}
{% endif %}
{% if institution.all.id == institution.parent_institution.id %}
{{institution.name}}
{% endif %}
{% for child in institutions.all %}
{% if child.id == institution.parent_institution.id %}
{{institution.name}}
{% endif %}
{% endfor %}
# views.py
class InstitutionDetail(DetailView):
model = Institution
def get(self, request, *args, **kwargs):
institutions_child = Institution.objects.filter(parent_institution__isnull=True).prefetch_related('parent_institution_set')
institutions = get_object_or_404(Institution, pk=kwargs['pk'])
context = {'institutions_child': institutions_child, 'institutions': institutions}
return render(request, 'stakeholders/institution_detail.html', context)
{% for child_node in institutions.parent_institution_set.all %}
{{child_node.name}}
{% endfor %}
I either get None or the current institutions name (A).
Does anyone know how I could achieve the goal of getting all the child institutions in the detail view?
Any help is appreciated! :)
The Foreign Key in opposite direction returns a queryset, not a model instance.
<p><b>Child institution: </b></p>
<ul>
{% for child in institutions.child.all %}
<li>{{ child.name }}</li>
{% endfor %}
</ul>
Is it possible to iterate over a list of three context variables shown below so that depending on the user's attribute (in this instance grade, Grade 10, Grade 11, Grade 12). If current user's grade attribute is Grade 10 then they only get: context['grade10'] from below.
Current view:
class SumListView(ListView):
model = Summaries
template_name = 'exam/summary.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['grade10'] = Summary.objects.filter(grade='Grade 10')
context['grade11'] = Summary.objects.filter(grade='Grade 11')
context['grade12'] = Summary.objects.filter(grade='Grade 12')
return context'''
Current html template block:
{% block content %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% endblock content %}
I tried this but it breaks the code since for loops and iterations are mixing:
{% block content %}
{% if grade10 %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% elif grade11 %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% else grade12 %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% enif %}
{% endblock content %}
What is the best way to go about this?
I know I can write different urls for each context which in turn renders a different template but that does not seem efficient and I hope there is a better way to do that. Any help highly appreciated, including documentation pointers.
You can perform this logic in your view, you can use a single context variable but change it's contents based on your logic
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_grade = self.request.user.get_grade() # Replace with how you access the user's grade
context['grades'] = Summary.objects.filter(grade=user_grade)
return context
Then loop over grades in your template
I have two very simple classes for products and photos. I would like to present products on the main page of my store along with photos related to a foreign key. But I do not know how to do this, I found many answers to get this in the view using a join like 'prefetch_related' but my ID changes for each case. So how do you present your photos for each product? are there any Django tags about which I do not know?
my models.py
class Product(models.Model)
name = models.CharField(max_length=10)
class Image(models.Model)
image = models.ImageField()
name_related = models.ForeignKay(Product, on_delate=models.CASCADE)
views.py
def home(request):
product_list = Product.objects.all()[:12]
#img = ??
context = {'product_list': product_list,
}
return render(request, 'home.html', context)
home.html
{% for product in product_list %}
{{ product.name }}
<!-- {{ product.imge }} ' element presenting the first photo for each 'product' model'???-->
{% endfor %}
Any help will be appreciated.
Since a foreign relation has been established you can iterate through the related models from the parent model.
The related models are already accessible from the parent model without doing anything explicit.
In your template you can do this:
{% for product in product_list %}
{{ product.name }}
{% for product_image in product.image.all %}
<!-- Iterate through this products related images -->
{{ product_image.image.url }}
{% endfor %}
{% endfor %}
For performance reasons, you will want to prefetch the relations, or else for every product you will do an additional query, so, in your view you will want to add this:
product_list = Product.objects.all().prefetch_related('image')[:12]
Just do
{% for product in product_list %}
{{ product.name }}
{% for image in product.image.all %}
<!-- {{ image.image.url }} -->?
{% endfor %}
{% endfor %}
I'm trying to create a hierarchy view in Django, but I'm struggling to make sense of how to use QuerySets effectively.
What I'm aiming for eventually is a html page that displays courses like this:
Main Course 1 --- Child Course 1
--- Child Course 2
Main Course 2 --- Child Course 3
--- Child Course 4
Each group of courses would be wrapped in a div and styled etc.
In my view.py file I have the following:
class HierarchyView(generic.ListView):
template_name = 'curriculum/hierarchy.html'
def get_queryset(self):
return Offering.objects.all()
def get_context_data(self, **kwargs):
context = super(HierarchyView, self).get_context_data(**kwargs)
context['main'] = self.get_queryset().filter(course_type='M')
context['sub'] = self.get_queryset().filter(parent_code__in=context['main'])
return context
The Offering model is set up so that parent_code is a self-referential foreign key (i.e. any course can be a child of any other), like this:
...
parent_code = models.ForeignKey(
'self',
null=True,
blank=True,
on_delete=models.SET_NULL)
...
And in my html template I have:
{% for mainoffering in main %}
<div>
<div>{{ mainoffering.course_name }}</div>
{% for offering in sub %}
<div>{{ offering.course_name }}</div>
{% endfor %}
</div>
{% endfor %}
What this results in, however, is that all child courses appear under all main courses, regardless of whether or not they are actually children of that course, which is obviously not what I'm after.
I'm still learning the ropes in Django, and I'm struggling to find anything that explains in plain English what I need to do. Please help!
I think you would need to change your template to match each of the child courses to their parent courses. Maybe something like:
{% for mainoffering in main %}
<div>
<div>{{ mainoffering.course_name }}</div>
{% for offering in sub %}
{% if offering.parent_code == mainoffering %}
<div>{{ offering.course_name }}</div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
The context['sub'] will return all of them, without any grouping, ordering etc. You can do couple of things to get the desired behavior.
You can do a prefetch related.
from django.db.models import Prefetch
offerings = Offering.objects.filter(course_type='M').prefetch_related(
Prefetch(
"courses_subset",
queryset=Offering.objects.filter(parent_code__in=offerings),
to_attr="sub"
)
)
for o in offerings:
print o.sub
You can actually make this a method in your model and create a template tag (i'd most likely use this).
method in your Offering model
def get_child_courses(self):
child_courses = Offerings.objects.filter(parent_code=self.id)
return child_courses
template tag
#register.simple_tag
def get_child_courses(course):
return course.get_child_courses()
In your template:
{% for mainoffering in main %}
<div>
<div>{{ mainoffering.course_name }}</div>
{% for offering in mainoffering|get_child_course %}
<div>{{ offering.course_name }}</div>
{% endfor %}
</div>
{% endfor %}
You can group them in your template as suggested by accraze. I'd personally go for the second option
For example, let's say I have the following models:
class Group(models.Model):
group_name = models.CharField(max_length=20)
class Person(models.Model):
group = models.ForeignKey(Group)
name = models.CharField(max_length=50)
I want to list all groups, and for each group list the people in the group.
Group A: Person1, Person2, Person3
Group B: Person4, Person5, Person6
I get stuck at Group.objects.all(), which will only return a queryset containing the Group objects that I can cycle through in the template. I don't know how to cycle through the people in each group though. Help?
groups = Group.objects.all()
{% for g in groups %}
g.group_name:
<< Need an inner loop here to cycle through the people in each group? >>
{% endfor %}
{% for p in g.person_set.all %}
You can use the builtin regroup tag:
Template:
{% regroup people by group as people_by_group %}
{% for group in people_by_group %}
{{ group.grouper.group_name }}
{% for person in group.list %}
{{ person }}
{% endfor %}
{% endfor %}
Context:
{'people': Person.objects.all().select_related('group').order_by('group')}
This won't list empty groups, but you can build a similar strucutre in your own view, for example:
groups = list(Group.objects.all())
groups_map = dict((g.pk, g) for g in groups)
for g in groups:
g.person_cache = []
for person in Person.objects.all():
if person.group_id is not None:
groups_map[person.group_id].person_cache.append(person)
del groups_map
# ``groups`` now contains a list suitable for your template
This way you make only two queries. Using a related manager in a loop will produce number_of_groups+1 queries.
You need to actually query for the people instead of the group.
people = Person.objects.select_related().order_by('group')
{% for person in people %}
{% ifchanged person.group %}
{{ person.group }}
{% endifchanged %}
{{ person }}
{% endfor %}
This does one query for all people and their related groups, ordered by group. The ifchanged in the template recognizes when you've moved on to a new group and prints it out.
Hope that helps.