Query Django Object Lists of ForeignKey - python

I have a MenuSection model and a Product model. The Product model has MenuSection set as a ForeignKey. Everything works fine, except I am having difficulty figuring out how to query the Product model and listing out a list of objects unique to the ForeignKey, but print the ForeignKey value once at the top of the template.
Example of how I would like the Products printing to the template:
Salads (FK) <= Only printed once
Cobb (product.name)
Ceasar (product.name)
Pizza (FK)
Supreme (product.name)
Veggie (product.name)
...
Tag
#register.inclusion_tag('tags/_starters.html', takes_context=True)
def products(context):
product = Product.objects.all()
return {
'product': product,
'request': context['request'],
}
Tag Template
{% for p in product %}
<div class="menu-wrapper">
<div class="menu-description">
<h1>{{ p.section.name }}</h1> <======= This is the (FK) that I need to print once.
<div class="menu-list">
<h5>{{ p.name }}</h5>
<p class="price">
{% if p.price_b %}
{{ p.price_a }}/
{{ p.price_b }}
{% else %}
{{ p.price_a }}
{% endif %}
</p>
<span class="menu-dot-line"></span>
</div>
<p class="menu-ingredients">{{ p.description }}</p>
</div>
</div>
{% endfor %}
Model
#register_snippet
class Product(ClusterableModel):
section = models.ForeignKey(MenuSection, verbose_name='Menu Section')
name = models.CharField(max_length=255, verbose_name='Menu Item Name')
...

Instead of querying Product in your tag, return
return {
'menu_sections': MenuSection.objects.all()
}
Then, in your template,
{% for menu_section in menu_sections %}
{{ menu_section.name }}
{% for product in menu_section.product_set.all %}
{{ product.name }}
{% endfor %}
{% endfor %}

Related

How to merge Django queryset result, collecting values from matching keys?

My Views.py
context['user'] = User.objects.filter(code='01').values('name', 'phone')
print(context['user'])
The current results are as follows:
<QuerySet [{'name': 'John', 'cellphone': '1234567890'}, {'name': 'Doe', 'cellphone': '1234512345'}]>
How can I get a result like this from templates?
{% for u in user %}
<span>name :</span> <span> {{ u.name }} / </span>
<span>cellphone :</span> <span> {{ u.cellphone }}</span>
{% endfor %}
# want result
name : John, Doe / cellphone : 1234567890, 1234512345
Loop twice.
<span>name :</span>
{% for u in user %}
{% if not forloop.first %}, {% endif %}{{ u.name }}
{% endfor %}
<span> / cellphone :</span>
{% for u in user %}
{% if not forloop.first %}, {% endif %}{{ u.cellphone }}
{% endfor %}

How to list objects of the same date?

I want to list all items in my template, but I want to list items under the same year. For example,
under the 2021 title, model objects for that year should be listed. Year titles should come dynamically. How can I do it?
views.py
def press_list(request):
press_contents = PressContent.objects.all().order_by('-date')
context = {
'press_contents': press_contents
}
return render(request, "press_list.html", context)
models.py
class PressContent(models.Model):
label = models.CharField(max_length=500)
url = models.URLField(max_length=500)
date = models.DateTimeField(blank=True, null=True)
press_list.html
{% for press in press_contents %}
<div class="card" style="width: 18rem; margin:15px">
<div class="card-header">
{{ press.date.year }}
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">{{ press.label }}</li>
# Other objects from this year should come here.
</ul>
</div>
{% endfor %}
To be clear:
2021
obj 1
obj 2
2020
obj 3
obj 4
...
...
You can work with the {% regroup … by … %} template tag [Django-doc]:
{% regroup press_contents by year as pressitems %}
{% for pressyear in pressitems %}
<div class="card" style="width: 18rem; margin:15px">
<div class="card-header">
{{ pressyear.grouper }}
</div>
<ul class="list-group list-group-flush">
{% for press in pressyear.list %}
<li class="list-group-item">{{ press.label }}</li>
# Other objects from this year should come here.
{% endfor %}
</ul>
</div>
{% endfor %}
If you can afford to convert a queryset into a list of objects, then you can use the built-in template filter regroup (I think, I've never used it).
Another approach would be to write a python generator function and pass it in the context, to be iterated over by the template. This avoids issues with resource consumption when the queryset comprises a large number of objects. Something like
def year_grouper():
qs = PressContent.objects.all().order_by('-date')
last_object_year = 1000000000
for obj in qs:
obj.year_changed = ( obj.date.year != last_object_year )
yield obj
last_object_year = obj.date.year
and
{% for obj in year_grouper %}
{% if obj.year_changed %}
... year header, etc.
{% endif %}
... display obj
{% endfor %}

Django template, loop through items if their id is equal to parent loop name

I'm trying to loop through different Zones and then show the items which are part of this zone
Zone is a model, has a name and a ForeignKey. Planche is a model which has Zone as ForeignKey.
I'm looping through zones to display each zone. In that loop I'm looping all Planches and would like to display only the ones that have Zone as a ForeignKey.
class Zones(models.Model):
name = models.CharField(max_length=30)
genre = models.ForeignKey(ZoneTypes, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Planche(models.Model):
pzone = models.ForeignKey(Zones, on_delete=models.CASCADE)
ref = models.CharField(max_length=5, default="1")
length = models.IntegerField()
width = models.IntegerField()
orientation = models.CharField(max_length=30)
def __str__(self):
return self.ref
Template
<div>
<h1>My list of planches</h1>
</div>
{% for z in zones %}
<div>
<h2>Zone name: {{ z.name }}</h2>
{% for p in planches %}
{% if p.pzone == z.name }
<h1>Ref: {{ p.ref }}</h1>
<p>Length: {{ p.length }} - Width: {{ p.width }}</p>
<p>Orientation: {{ p.orientation }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
{% if p.pzone = z.name %} returns False,
They both return the same string if I just display them {{ p.pzone }} and {{ z.name }} but I guess they aren't the same data type. I tried converting them to strings in a {% with %} statement but I keep failing
I'm assuming you want to display all the planches for each zone. You can use the related_name on the ForeignKey to access to items referencing the current object. You did not set any related name there, so it's the default one: planche_set.
<div>
<h1>My list of planches</h1>
</div>
{% for z in zones %}
<div>
<h2>Zone name: {{ z.name }}</h2>
{% for p in z.planche_set.all %}
<h1>Ref: {{ p.ref }}</h1>
<p>Length: {{ p.length }} - Width: {{ p.width }}</p>
<p>Orientation: {{ p.orientation }}
{% endfor %}
</div>
{% endfor %}
Be aware that method will execute N+1 queries (One to select your zones then one query per zone to retrieve the planches of each zone) unless you add prefetch_related('planche') in the view where your select your zones.
References:
Official documentation about backward relationships
What is `related_name` used for in Django?
If you want to display Planches for every Zones, you can write the second loop like this:
<div>
<h1>My list of planches</h1>
</div>
{% for z in zones %}
<div>
<h2>Zone name: {{ z.name }}</h2>
{% for p in z.planche_set.all %}
<h1>Ref: {{ p.ref }}</h1>
<p>Length: {{ p.length }} - Width: {{ p.width }}</p>
<p>Orientation: {{ p.orientation }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
Here is example from another post: Django foreign key relation in template

To how list group by values and values in that category

I want my template to display my group by category as a header, and then all the values for that group by category under it. For example, my table looks like this:
['John','Physics']
['Jim','Physics']
['Sam','Biology']
['Sarah','Biology']
And I want the template to output this:
Physics
John
Jim
Biology
Sam
Sarah
I'm not sure what to put in my veiws.py as I would usually do this in SQL --> first group by category, then return all results in that category.
How would my veiws.py and template looks like to accomplish this? Thanks.
My current veiws.py:
def department(request):
students = Students.objects.all().order_by('department')
return render(request, 'department.html', {
'students':students,
})
Here is my model.py
class Mentors(models.Model):
name = models.CharField(max_length=100)
degree = models.CharField(max_length=100)
department = models.CharField(max_length=100)
And my template:
{% if mentors %}
<div class="row">
{% for mentor in mentors %}
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
<h3>{{ mentor.department }}</h3>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
<div class="thumbnail">
<img src="{{ mentor.image.url }}" class="img-thumbnail">
<div class="caption">
<h4 class="text-center">{{ mentor.name }}, {{ mentor.degree }}</h4>
<p class="text-center"><small>{{ mentor.department }}</small></p>
</div>
</div>
</div>
{% endfor%}
</div><!-- /.end row -->
{% endif %}
The template (department.html) is the place where you're going to list all the student. You must have some similar to this:
{% if students %}
{% for student in students %}
<p>{{ student.NAME_FIELD }}</p>
{{ student.DEPARTMENT_FIELD}}
{% endfor %}
{% else %}
No student are available.
{% endif %}
NAME_FIELD and DEPARTMENT_FIELD are the fields you declared in your model.py

Django Filter Objects and Get First Corresponding Values

I have two models.
class House(models.Model):
name= models.Charfield(max_length=100)
city= models.Charfield(max_length=100)
area= models.CharField(max_length=200)
country=models.CharField(max_length=30)
class HouseRooms(models.Model):
room_name=models.Charfield(max_length=200)
house= models.ForeignKey(House, related_name='house_hr')
room_price=models.PositiveIntegerField()
When a user run a keyword search, I want to return the name of each 'House' and the first room_price of the corresponding 'HouseRooms'. See my views below.
def my_house_search(request):
query_string= ''
rms= None
sms=None
if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q']
entry_query= get_query(query_string, ['city','country',])
rms= House.objects.filter(entry_query).order_by('-pub_date')
sms= HouseRooms.objects.filter(house_id__in=rms)
return render(request, 'search/my_house_search.html',{'rms':rms, 'sms':sms, 'query_string':query_string})
Template:
{% if query_string %}
<p> Results </p>
{% if rms %}
{% for m in rms %}
<p> Name: {{ m.name }} </p>
{% empty %}
<p> No house found </p>
{% endfor %}
{% for sd in sms %}
<p> price: {{ sd.room_price }} for {{sd.room_name}}</p>
{% empty %}
<p> no price found </p>
{% endfor %}
{% endif %}
{% endif %}
With the code I wrote, it will return the name of each house and show all prices to all houses like this:
Coker House
Klopp House
$50/day for small room
$100/day for medium room
$200/day for big room
$200/day for quack room
$400/day for master room
$500/day for big room
I just want it to return the result like this.
Coker House
$50/day for small room
Klopp House
$200/day for quack room
What am I missing? How do I go about this?
You shouldn't query HouseRooms explicitly in the view. Instead, you can use the reverse relationship accessor inside your iteration in the template itself.
{% for m in rms %}
<p> Name: {{ m.name }} </p>
{% with m.house_hr.first as sd %}
{% if sd %}
<p> price: {{ sd.room_price }} for {{sd.room_name}}</p>
{% else %}
<p> no price found </p>
{% endif %}
{% endwith %}
{% empty %}
<p> No house found </p>
{% endfor %}

Categories