How to display objects grouped by foreign key - python

I'm a django n00b and am lost on how to do this.
sample models:
class Food_Type(models.Model):
name = models.CharField(max_length=200)
class Food(models.Model):
name = models.CharField(max_length=200)
food_type = models.ForeignKey(Food_Type)
And some data:
v = Food_Type(name='Veggie')
f = Food_Type(name='Fruit')
c = Food(food_type=v, name='carrot')
a = Food(food_type=f, name='apple')
The HTML output should look something like this:
Veggie
carrot
Fruit
apple
I'm uncertain of the right way to do the grouping, I assume the view and not the template.
food_type_list = Food_Type.objects.all().order_by('name')
food_list = []
for ft in food_type_list:
food_list.append(Food.objects.filter(fruit_type__exact=device_type.id)
render_to_response(some_template,
{'food_type': food_type_list, 'foods': food_list}
)
based on my view, I'm uncertain how to display
Does not work and there has got to be a better way
{% for type in food_type %}
{{ type }}
{% for food in foods %}
{% if food.food_type == type %}
{{ food.name }}
{% endif %}
{% endfor %}
{% endfor %}

I think you are looking for regroup
food = Food.objects.all()
{% regroup food by food_type as food_list %}
<ul>
{% for food_type in food_list %}
<li>{{ food_type.grouper }}
<ul>
{% for item in food_type.list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>

Simple:
Food.objects.order_by('food_type__name')

Related

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>

django sort dict after query

have a table with websites and a many to one table with descriptions
trying to get a list, firstly getting the latest descriptions and then displaying them ordered by the content of the descriptions...
have the following in views.py
def category(request, category_name_slug):
"""Category Page"""
context_dict = {}
try:
category = Category.objects.get(slug=category_name_slug)
subcategory = SubCategory.objects.filter(category=category)
websites = Website.objects.filter(sub_categories=subcategory, online=True, banned=False)
sites = websites
descriptions = WebsiteDescription.objects.prefetch_related("about")
descriptions = descriptions.filter(about__in=sites)
descriptions = descriptions.order_by('about', '-updated')
descs = []
last_site = "" # The latest site selected
# Select the first (the latest) from each site group
for desc in descriptions:
if last_site != desc.about.id:
last_site = desc.about.id
desc.url = desc.about.url
desc.hs_id = desc.about.id
desc.banned = desc.about.banned
desc.referral = desc.about.referral
descs.append(desc)
context_dict['descs'] = descs
context_dict['websites'] = websites
context_dict['subcategory'] = subcategory
context_dict['category'] = category
except SubCategory.DoesNotExist:
pass
return render(request, 'category.html', context_dict)
this gives me a list with sites and their latest descriptions, so i have the following in category.html
{% if category %}
<h1>{{ category.name }}</h1>
{% for subcategory in category.subcategory_set.all %}
{{ subcategory.name }} ({{ subcategory.website_set.all|length }})
{% endfor %}
{% if descs %}
{% load endless %}
{% paginate descs %}
{% for desc in descs|dictsortreversed:"description"|dictsortreversed:"officialInfo" %}
<ul id='list' class='linksteps'>
<a href="/{{ desc.about_id }}" rel="nofollow" target="_blank">
<img src="/static/screenshots/{{ desc.about_id }}.png" />
</a>
<li><h3>{{ desc.about_id }}{% if desc.title %} - {{ desc.title }} {% endif %}</h3>
{% if desc.description %}<b>Description: </b>{{ desc.description }}
<br />{% endif %} {% if desc.subject %}<b>Keywords: </b>{{ desc.subject }}
<br />{% endif %} {% if desc.type %}<b>Type: </b>{{ desc.type }}
<br />{% endif %} {% if desc.officialInfo %} {% if desc.language %}<b>Language: </b>{{ desc.language }}
<br />{% endif %} {% if desc.contactInformation %}<b>Contact info: </b>{{ desc.contactInformation }}
<br />{% endif %}
{% else %}
{% endif %}
</li>
</ul>
</div>
{% endfor %}
{% show_pages %}
{% else %}
<strong>No websites currently in category.</strong>
{% endif %}
{% else %}
The specified subcategory {{ category_name }} does not exist!
{% endif %}
Initially i used dictsort
{% for desc in descs|dictsortreversed:"description"|dictsortreversed:"officialInfo"|dictsortreversed:"referral" %}
to give me the list in the desired order, so i was all happy ;)
Then however i decided i needed some pagination because the lists became too long.
django-endless-pagination works fine and does what its supposed too, however it splits up my list before the dictsort kicks in.
is there a way to sort before pagination happens and after i ordered_by at the initial query to have the latest descriptions selected?
much obliged
EDIT:
not getting any answers so my question might not be clear.
as far as i understand i need to sort the values in context_dict at the end in views.py replacing the dictsort as in the template
SOLVED:::
doing this did the trick for me to replace the dictsort.
descs1 = sorted(descs, key=operator.attrgetter('referral', 'officialInfo', 'description'), reverse=True)
context_dict['descs'] = descs1
SOLVED:::
doing this did the trick for me to replace the dictsort.
descs1 = sorted(descs, key=operator.attrgetter('referral', 'officialInfo', 'description'), reverse=True)
context_dict['descs'] = descs1

Paginating based on the alphabet (A-Z)

I have a simple contacts application where I want to paginate the contact list based on first name alphabet.
Here is my views.py
def contacts(request):
contact_list = Contact.objects.filter(user=request.user).order_by('first_name')
pages = [contact_list.filter(first_name__istartswith=i) for i in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
return render(request, 'contact/contact.html', {'contact_list': contact_list, 'pages': pages})
Here is my template
{% for alphabet in pages %}
{% if alphabet %}
<p>{{ alphabet }}</p>
{% for contact in contact_list %}
{% if contact in pages %}
<ul>
<li>{{ contact.first_name }}</li>
</ul>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
The output from this is something like
[<Contact: Steve>, <Contact: Su>]
Steve
Su
[<Contact: Ted>]
Ted
[<Contact: Zedd>]
Zedd
The {{ alphabet }} prints a list. What should I write to print the alphabet instead?
Capture the alphabet in the context variable:
pages = [{"letter": i, "contacts": contact_list.filter(first_name__istartswith=i) }
for i in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
return render(request, 'contact/contact.html', {'pages': pages}) # why pass contact_list?
Your template should be simplified to:
{% for alphabet in pages %}
{% if alphabet.contacts %}
<p>{{ alphabet.letter }}</p>
{% for contact in alphabet.contacts %}
<ul>
<li>{{ contact.first_name }}</li>
</ul>
{% endfor %}
{% endif %}
{% endfor %}

Iterate Items in Their Specific Groups in Django

In my Django template I want to be able to iterate through groups and items, but I want to iterate the items underneath their group. So far I have them iterating like this but it does not show which groups the items are a part of. How would I iterate the template to get this inclusion?
Views:
def manage(request):
group_list = Group.objects.order_by('name').filter(user=request.user)
item_list = Item.objects.order_by('name').filter(user=request.user)
return render(request, 'manage.html', {'group_list': group_list, 'item_list': item_list})
Template:
{% extends "base.html" %}
{% block content %}
{% for group in group_list %}
{{ group.name }}<br />
{% endfor %}
{% for item in item_list %}
{{ item.name }}<br />
{% endfor %}
{% endblock %}
UPDATE
Models (Sorry forgot to include this):
class Group(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=30)
class Item(models.Model):
user = models.ForeignKey(User)
group = models.ManyToManyField(Group)
name = models.CharField(max_length=30)
Your approach does unneccessary additional database hits. For performance reasons you should select just the items with related groups like this:
def manage(request):
item_list = Item.objects.order_by(
'group__name', 'name').filter(
user=request.user).select_related('group')
return render(request, 'manage.html', {'item_list': item_list})
The template looks like this:
{% extends "base.html" %}
{% block content %}
{% for item in item_list %}
{% ifchanged item.group.name %}
{{ item.group.name }}<br />
{% endifchanged %}
{{ item.name }}<br />
{% endfor %}
{% endblock %}
That way you only have ONE database hit regardless of how many groups there are.
I guess you have a fk from item to group
class Item(models.Model):
group = models.ForeignKey(Group)
views:
def manage(request):
group_list = Group.objects.order_by('name').filter(user=request.user)
return render(request, 'manage.html', {'group_list': group_list})
template:
{% extends "base.html" %}
{% block content %}
{% for group in group_list %}
{{ group.name }}<br />
<p>Item for this group</p>
{% for item in group.item_set.all %}
{{item.name}}
{% endfor %}
{% endfor %}
{% endblock %}

django template - for loop over 2 querysets

I am getting 2 querysets from db:
all_locations = Locations.objects.all()[:5]
rating = Rating.objects.all()[:5]
return render_to_response('index.html',{'all':all_locations,'rating':rating},context_instance=RequestContext(request))
But I am stuck here, not knowing how to loop over these 2 querysets in one loop. this is being wrong:
{% if all and rating %}
{% for every in all and rating %}
{{every.locationname}}, {{every.rating_score}}
{% endfor %}
{% endif %}
You can try zip(all_locations, rating). It will produce a list of tuples. Then you can iterate over them in pairs. Here is an example: (demo)
all_locations = ['ca','ny','fl']
ratings = ['best','great','good']
for (l,r) in zip(all_locations,ratings):
print l+':'+r
Outputs
ca:best
ny:great
fl:good
I have also come across this problem. Now I've fixed it.
what I do is using
new=tuple(zip(queryset1,queryset2))
return render(request, 'template.html', {"n": new}).
in view.py.
In template.html, I use three for sentences which are list below.
{% for i in n %}
{% for j in i|slice:"0:1" %}
......operate queryset1
{% endfor %}
{% for z in i|slice:"1:2" %}
.....operate queryset2
{% endfor %}
{% endfor %}
It seems this method will fulfill your needs.
this might work:
{% with rating|length as range %}
{% for _ in range %}
{{ rating[forloop.counter] }}
{{ location[forloop.counter] }}
{% endfor %}
{% endwith %}
i'm not sure if rating|length will to the job... you might need to add rating|length|times' withtimes` filter defined as:
#register.filter(name='times')
def times(number):
return range(number)

Categories

Resources