Django - Looping over unique model field in template - python

I have a model which a choice field, category, which the user must enter when submitting an entry. I would like to create a view in which each category has its own heading (only once), therefore each unique category would have its own heading, and then display the title associated to each category.
models.py
class Position(models.Model):
club_functions = Choices('Corporate Relations', 'Events & Conference', 'Marketing & Operations', 'Software Development', 'Product')
title = models.CharField(max_length=50)
category = models.CharField(choices=club_functions, max_length=30, blank=False)
description = models.TextField(blank=True)
spec_q1 = models.CharField(max_length=500)
spec_q2 = models.CharField(max_length=500)
views.py
def position_list_view(request):
all_objects = Position.objects.all()
context = {
'object_list' : all_objects
}
return render(request, "exec_list.html", context)
exec_list.html
{% for object.category in object_list %}
<h3>{{ object.category }}</h3>
<p>{{ object.title }}</p>
{% endfor %}
Any ideas on how to do this?

you can use regroup
{% regroup object_list by category as category_list %}
<ul>
{% for category in category_list %}
<li>{{ category.grouper }}
<ul>
{% for position in category.list %}
<li>{{ position.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>

Related

How do i work with 3 django models linked by a foreign field?

I've been able to display all offices in an election, but have been unable to display all candidates in an office on the same page
models.py
class Election(models.Model):
name = models.CharField(max_length = 30)
slug = models.SlugField(max_length = 250, null = False, unique = True)
class Office(models.Model):
election = models.ForeignKey(Election, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length = 30)
class Candidate(models.Model):
office = models.ForeignKey(Office, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length = 30)
views.py
def poll(request, id):
context = {
'election' : Election.objects.get(pk=id),
'off' : Office.objects.all()
}
return render(request, 'poll.html', context)
poll.html
{% for office in election.office_set.all %}
<div class="text-center">
<h3>{{ office.name }}</h3>
{% for candidate in off.candidate_set.all %}
<h5>{{ candidate.name }}</h5>
{% endfor %}
</div>
{% endfor %}
In your first line of poll.html, you call "office" from the queryset "election.office_set.all"
Therefore, when you call a subquery of that QS, you have to reference the original name, ie: office, rather than off.
Your final code should look like this:
poll.html
{% for office in election.office_set.all %}
<div class="text-center">
<h3>{{ office.name }}</h3>
{% for candidate in office.candidate_set.all %}
<h5>{{ candidate.name }}</h5>
{% endfor %}
</div>
{% endfor %}
You also don't need the line
'off' : Office.objects.all()
in your Views.py.

Could not parse the remainder:

I saw many questions about this error, but all are distincts and not apply to me, so...
My models.py
# Category
class Category(models.Model):
category_name = models.CharField(max_length=64)
def __str__(self):
return f"{self.category_name}"
# Item
class Item(models.Model):
item_name = models.CharField(max_length=64)
category = models.ForeignKey(Category, on_delete= models.CASCADE, related_name="items_by_category")
price_small = models.DecimalField(help_text="Price in U$S",max_digits=6, decimal_places=2, default= 0)
price_large = models.DecimalField(help_text="Price in U$S",max_digits=6, decimal_places=2, default= 0)
nradd = models.IntegerField(default=0)
def __str__(self):
return f"{self.category} {self.item_name} - Qty.of Adds: {self.nradd} - Price Small: {self.price_small} - Price Large: {self.price_large}"
My views.py
def menu(request):
products = list(Item.objects.all().values().order_by('category'))
categories = list(Category.objects.all().prefetch_related('items_by_category'))
extras = list(Extra.objects.filter(category="T"))
subsextras = list(Extra.objects.filter(category="S"))
context = {
'Products' : products,
'Categories': categories,
'Extras' : extras,
'Subextras' : subsextras
}
return render(request, 'orders/menu.html',context)
First, I'm trying to simply list the categories with the items who belongs to:
My menu.html:
{% extends 'orders/base.html' %}
{% load static %}
{% block title %}
Menu
{% endblock %}
{% block body %}
<ul>
{% for cate in Categories %}
<li>{{ cate.category_name }}</li>
<ul>
{{% for myitem in cate.items_by_category.all %}}
<li>{{ myitem.item_name }}</li>
{{% endfor %}}
</ul>
{% endfor %}
</ul>
{% endblock %}
the error appears in the line:
{{% for myitem in cate.items_by_category.all %}}
Same commands in the shell goes well:
cate = Category.objects.get(category_name="Salads")
cate.items_by_category.all()
Thanks in advance,
It's about Template Language.
Variables look like this: {{ variable }}.
Filters look like this: {{ name|lower }}.
Tags look like this: {% tag %}.
To comment-out part of a line in a template, use the comment syntax:
{# #}
There is no such thing as {{% %}}
So, instead of
{{% for myitem in cate.items_by_category.all %}}
You should use
{% for myitem in cate.items_by_category.all %}
Reference:
https://docs.djangoproject.com/en/3.0/ref/templates/language/
The template tags are sourrounded with {% … %}, not {{% … %}}. So you should rewrite the template to:
{% extends 'orders/base.html' %}
{% load static %}
{% block title %}
Menu
{% endblock %}
{% block body %}
<ul>
{% for cate in Categories %}
<li>{{ cate.category_name }}</li>
<ul>
{% for myitem in cate.items_by_category.all %}
<li>{{ myitem.item_name }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>

Value is none when calling out a value of foreign key

I am trying to display a brand of a bike, but the value shows as None.
Models.py:
class Bike(models.Model):
item = models.OneToOneField(Item, on_delete=models.CASCADE)
brand = models.ManyToManyField(Brand, null=True)
class Brand(models.Model):
name = models.CharField(max_length=20)
and here's my template:
{% for item in items %}
{{ item.bike.brand.name }} {{ item.title }}
{% endfor %}
I am calling the brand by {{ item.bike.brand.name }} and it displays as None for every Bike
if your view is like this,
class BikeListView(ListView):
model = Bike
template_name = '----.html'
you can call it in your templates as
{% for obj in object_list %}
{{ obj.field_name in your item model }}
{% for brand_name in obj.brand.all %}
{{ brand_name.name }}
{% endfor %}{% endfor %}

Template in Django doesn't show same content for 2 paths

For this template, everything will show fine, but only for the first course. If I add lectures for another course, template won't show them.
def courses(request, slug):
con = get_object_or_404(Course, slug=slug)
context = {
'course': con,
'lectures': con.lectures.all(),
'categories': con.categories.all(),
}
return render(request, 'courses/courses.html', context)
<ul>
{% for a in categories %}
<li><strong>{{ a.course_category }}</strong></li>
{% for c in lectures %}
{% if a == c.course_category %}
<li>{{ c.lecture_title }}</li>
<li>{{ c.content }}</li>
{% if c.link %}
<li>{{ c.link }}</li>
{% endif %}
{% if c.file %}
<li><a href='{{ MEDIA_URL }}{{ c.file.url }}'>download</a></li>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
</ul>
class Course(models.Model):
study_programme = models.ForeignKey('StudyProgramme', on_delete=models.CASCADE)
name = models.CharField(max_length=50)
ects = models.PositiveSmallIntegerField(validators=[MaxValueValidator(99)])
description = models.TextField()
year = models.PositiveSmallIntegerField(validators=[MaxValueValidator(99)])
semester = models.IntegerField(choices=((1, "1"),
(2, "2"),
), default=None)
slug = models.SlugField(max_length=140, unique=True)
def __str__(self):
return self.name
def _get_unique_slug(self):
slug = slugify(self.name)
unique_slug = slug
num = 1
while Course.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, num)
num += 1
return unique_slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self._get_unique_slug()
super().save()
class CourseCategory(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE, related_name='categories')
course_category = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.course_category
class Lecture(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures')
This is the Course model that is present in my models.py. It uses slug for links.
I think your Lecture model has a problem.
Why does your Lecture model's course field has default=''?
It should be one of your Courcse model objects. If you want to add default value, you can use like this
DEFAULT_COURSE = 1
class Lecture(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE, default=DEFAULT_COURSE, related_name='lectures')
Hope this helps:
You need two views for this, each doing only the database queries they actually need and handle all the data preparation.
This way, you get nice and clean templates.
First View: /courses
def courses(request):
queryset = Course.objects.all()
context = {'courses':queryset}
return render(request, 'courses/courses.html', context)
template for this (courses.html):
<ul>
{% for i in courses %}
<li>
<a href={{ i.slug }}>{{ i }}</a>
</li>
{% endfor %}
</ul>
Second View: /courses/course_name
def course_detail(request, course_name):
query = Course.object.get(name=course_name)
context = {'lectures':query.lectures.all(),'categories':query.categories.all()}
return render(request, 'courses/course_detail.html', context)
template for this (course_detail.html):
<p><strong>Categories</strong></p>
<ul>
{% for c in categories %}
<li>{{ c.course_category }}<li>
{% endfor %}
</ul>
<p><strong>Lectures</strong></p>
<ul>
{% for l in lectures %}
<li>{{ l.lecture_title }}</li>
<li>{{ l.content }}</li>
{% if l.link %}
<li>{{ l.link }}</li>
{% endif %}
{% if l.file %}
<li><a href='{{ MEDIA_URL }}{{ l.file.url }}'>download</a></li>
{% endif %}
<hr>
{% endfor %}
</ul>

how to filter story by it's belonging tag

I have two models news and category, and in news I have foreignkey of category. I know how to display news with same category in a single template. but furthermore, in my home page I'm trying to display featured news of each category. this is where I'm having problem.
this is my models.py
class News(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
category = models.ForeignKey("Tag")
active = models.BooleanField(default=True)
featured = models.BooleanField(default=False)
top = models.BooleanField(default=False)
slug = models.CharField(max_length=255, unique=True)
featuredInCat = models.BooleanField(default=False)
objects = StoryManager()
class NewsQueryset(models.query.QuerySet):
def active(self):
return self.filter(active=True)
def featuredInCat(self):
return self.filter(featuredInCat=True)
class NewsManager(models.Manager):
def get_queryset(self):
return NewsQueryset(self.model, using=self._db)
def get_featuredInCat(self):
return self.get_queryset().active().featuredInCat()
def all(self):
return self.get_queryset().active()
class Category(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(max_length=5000, null=True, blank=True)
In views.py
def category_list(request):
categoryList = NewsCategory.objects.all()
featuredInCat = News.objects.get_featuredInCat()
context = {
"featuredInCat":featuredInCat
"categoryList":categoryList,
}
return render(request,"news/category_list.html", context)
In my template
{% for category in categoryList %}
<div class='col-sm-4'>
<div id="container">{{category.title}}</h1>
<ul>
{% for x in featuredInCat %}
{{x.title}}</li>
{% endfor %}
</ul>
</div>
<hr>
</div>
{% endfor %}
then this shows the featuredInCat in every category where featuredInCat should be shown only in its Category section.
how do I fix this?
Take a look at the built-in regroup template tag of django. You will need to change your template to something like this:
{% regroup featuredInCat by category as news_list %}
<ul>
{% for news in news_list %}
<li>{{ news.grouper.title }}
<ul>
{% for item in news.list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
You can change your for loop to iterate over the correct objects
{% for x in category.news_set.get_featuredInCat %}
You won't need the context variable anymore

Categories

Resources