Django iteration (for ... in ...) how to put it in different divs? - django

I have few instances of model.
my model:
class Record(models.Model):
name = models.ForeignKey(Car)
image = models.ImageField(upload_to='images/')
created = models.DateTimeField(
default=timezone.now)
view:
def allrecords(request):
records = Record.objects.all().order_by('created')
return render(request, 'mycar/allrecords.html', {'records' : records})
I want show it on my website. In my template i have:
{% for record in records %}
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endfor %}
Now i get list of my records, but i would like put the newest record to first div, next to second etc. How can i do that?
I show simple screen how i would like have that (if someone will create new record, it will go to first div and other records will change place. Is any possibility to do something like that?
edit:
<div>
{% for record in records %}
{% if forloop.counter == 1 %}
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
{% endfor %}
</div>
<div>
{% for record in records %}
{% if forloop.counter == 2 %}
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
{% endfor %}
</div>
.
.
# till your 5th image

You can use forloop.counter to get the iteration number and check what is the iteration the loop and handle data accordingly.
In addition you can use CSS to make the layout work as you want.
Here is the information for Django template counter
Edit :
{% for record in records %}
<div>
{% if forloop.counter == 1 %}
# Here you can get your first images
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
</div>
<div>
{% if forloop.counter == 2 %}
# Here you can get your first images
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
</div>
.
.
# till your 5th image
{% endfor %}

There are two ways to do this. If you want to set this option for a single view then:
def all_records(request):
records = Record.objects.all().order_by('-created')
return render(request, 'mycar/allrecords.html', {'records' : records})
You're almost correct but order_by('created') leads to asceding order while order_by('-created') leads to descending order which is what you require.
Alternatively, if you want to have this setting to apply to all views then set class Meta in your models.py which will ensure that wherever you use Record.objects.all() it returns Records in descending order of created field:
class Record(models.Model):
name = models.ForeignKey(Car)
image = models.ImageField(upload_to='images/')
created = models.DateTimeField(
default=timezone.now)
class Meta:
ordering = ('-created')
It's Django design pattern to make all logical decisions in models and views and only just plugin formatted data in templates. You shouldn't add any complex logic in templates.

I'm assuming the question means that the model might have more than 5 records. If so, a more generic solution would be
<div class='row'>
<div class='firstimage'>
<img src={{ records[0].image.url}}/>
{{record.name}}
</div>
{% for record in records %}
{% if forloop.counter > 1 %}
<div class='subsequentimage'>
<img src={{ record.image.url}}/>
{{record.name}}
</div>
{% endif %}
{% cycle "" "</div><div class='row'>" "" %}
{% endfor %}
</div>
Note the use of the 'cycle' tag to begin a new row div every third cell div.
I don't know what your CSS classes are to distinguish between rows and cells so I used 'row', 'firstimage' (which might be defined to take up twice as much width) and 'subsequentimage' as example classes.

I recommend you to use the context variables:
def all_records(request):
records = Record.objects.all().order_by('-created')
newest = records[:5]
oldest = records[5:]
return render(request, 'mycar/allrecords.html', {'newst' : newest,
'oldest': oldest })
In your template :
{% for new in newst %}
<div>what you want with news</div>
{% endfor %}
{% for old in oldest %}
<div>what you want with olds</div>
{% endfor %}

Related

Iterate context variables in Django templates based on user's attributes

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

How to display content in grid format in django template when receiving dynamic data in terms of list from database?

In django model I have created a multiselectfield for suppose wishlist where user can select multiple wishes from the available choices.
I am storing this data in comma separated format when it comes to displaying this on template things are pretty easy.
But, I want this data to be displayed dynamically as one row with two columns and as soon as two columns are filled and there is more data left to be displayed logic should should have the capability to create a new row and display the remaining content on the django-template.
For reference:
# models.py
class Wishlist(models.Model):
wishlist = (
('W1',"Buy a big masion"),
('W2',"Buy worlds fastest car"),
('W3',"Visit Europe"),
('W4',"Travel on bike to mountains")
)
your_wishlist = MultiSelectField(choices=wishlist)
# views.py
def index(request):
wishlist = Wishlist.objects.all()
context = {
"wishlist":wishlist
}
return render(request,'demolistingapp/index.html',context)
# index.html
{% load app_filters %}
{% block content %}
<h1>INDEX LISTING APP</h1>
{% if wishlist %}
{% for each_wish in wishlist %}
{% with each_wish.your_wishlist|split:"," as wish %}
{% for mywish in wish %}
<p>{{mywish}}</p><br>
{% endfor %}
{% endwith %}
{% endfor %}
{% endif %}
{% endblock %}
I have registered the custom filter split which returns a list.
I want the data to be displayed in terms of grid by maintaining two columns.
Sample output:
enter image description here
You could use cycle in the templates to create different class:
<p class="{% cycle row_left row_right %}">{{ mywish }}</p>
with adequate css (float/clear or inline-block;width:50%).
I would wrap your outer for loop in a HTML element with a class, then apply a grid layout to that class in your stylesheet. Wrapping each wish in a div element with a particular class will help you with further styling too.
<div class="wishlist">
{% for each_wish in wishlist %}
{% with each_wish.your_wishlist|split:"," as wish %}
{% for mywish in wish %}
<div class="wish">
<p>{{mywish}}</p>
</div>
{% endfor %}
{% endwith %}
{% endfor %}
</div>
And in your CSS:
.wishlist {
display: -ms-grid;
display: grid;
-ms-grid-columns: 1fr 1fr;
grid-template-columns: 1fr 1fr;
}

How to make a div appear only once in a loop?

I've created a model Team in models.py in Django for which I've created in views.py the following code:
def team(request):
obj = Team.objects.all().order_by('?')
context = {'team': obj}
return render(request, 'website/team.html', context)
In HTML I've created a team loop which is displaying all the team members available.
{% for team in team %}
<div class="member animated delay1" data-effect="fadeInUp">
<div class="team-image">
<div class="teamDescription">
<p>{{ team.description }}</p>
</div>
<img src="{{ team.picture.url }}">
</div>
<div class="blueLine"></div>
<div class="team-name-function animated delay1" data-effect="fadeInUp">
<h5>{{ team.name }} {{ team.surname }}</h5>
<p>{{ team.title }}</p>
</div>
</div>
{% endfor %}
In this loop, I need to make available one div with the numbers of team members, which has to appear only once and randomly as team members. Currently I have <div class="number">{{ team.count }}</div> outside the loop.
How do I integrate the members counting in the loop and make it appear only once?
Thank you in advance for any solution!
In the view use teams instead of team: context = {'teams': obj}
create a random number between 1 and teams length in view
import random
....
random_number = random.randint(a,len(teams)) # insert it after teams
...
context = {
'team': obj,
'random' : random_number,
}
then in the template use {% for team in teams %}
and if you want to show teams length just one time it's possible to use
{% if forloop.counter==random %}
<div class="number">{{ teams.count }}</div>
{% endif %}

Django nested QuerySet yielding nothing

I am using Django 1.8 with Postgres 9.2 on a Windows 8 machine.
I have two pieces of nearly identical code from two of my projects. One works and the other doesn't.
Here's the code that works:
# views.py
from django.shortcuts import render
from models import Artist, Track
def music(request):
artists = Artist.objects.all().order_by('orderName')
artistTrackCollections = []
for artist in artists:
artist.tracks = Track.objects.filter(artist=artist).order_by('order')
artistTrackCollections.append(artist)
return render(request, 'music.html', {'artistTrackCollections': artistTrackCollections,})
And the relevant template code:
{% for artist in artistTrackCollections %}
<dl>
<dt>
{% if artist.website %}
<h2>{{ artist.name }}</h2>
{% else %}
<h2>{{ artist.name }}</h2>
{% endif %}
</dt>
<dd>
<ul>
{% for track in artist.tracks %}
<li>“{{ track.title }}”
<i>({{ track.album.title }})</i>
{% endfor %}
</ul>
</dd>
</dl>
{% endfor %}
Now here's pretty much the exact same code from a different project of mine that doesn't work anymore:
def index(request):
productList = PartModel.objects.filter(isBuild=True, isActive=True).order_by('name')
productCollection = []
for product in productList:
product.part_list = product.buildpart.all().order_by('family__type')[:5]
productCollection.append(product)
return render(request, 'index.html', { 'productCollection': productCollection, })
and its corresponding template:
{% for product in productCollection %}
<p>{{ product.name }}
<p>${{ product.price }}
<ul>
{% for part in product.part_list %}
<li>{{ part.family.type.name }} | {{ part.name }}
{% endfor %}
</ul>
{% endfor %}
This code used to work but now it doesn't. In the code that works I succeed in going through each artist and attaching that artist's tracks. In the code that fails I try to go through each PartModel instance that is a build and get that PartModel instance's corresponding parts. They are identical as far as I can tell. productCollection gets populated but the part_list data for some reason is blank. This leads me to believe the problem is with this line:
product.part_list = product.buildpart.all().order_by('family__type')[:5]
But I cannot discern the difference from this line:
artist.tracks = Track.objects.filter(artist=artist).order_by('order')
Thanks in advance for any help!

Render one queryset into 2 div columns (django template)

Is there a good way to render the enumeration of a queryset into two div columns?
Using 960 grid, I've got something to the effect of...
<div class="container_16">
<div class="grid_8 alpha"></div>
<div class="grid_8 omega"></div>
</div>
In Django, one model needs to have it's enumerated contents rendered in both of those columns, and preferably somewhat equally. For the moment, I've got some ugly code that in the view splits the QuerySet into 2 halves, and then each half is rendered in their respective column.
There's got to be a better way to do this, preferably using only the template rendering system?
Just for reference, here's how it "works" at the moment:
views.py
#render_to('template.html')
def main_athletics_page(request, *args, **kwargs):
sports = Sport.objects.all()
half = sports.count() / 2
return { 'sports_1' : sports[0:half], 'sports_2' : sports[half:] }
template.html
<div class="grid_8 alpha">
{% for sport in sports_1 %}
<!-- Blah blah -->
{% endfor %}
</div>
<div class="grid_8 omega">
{% for sport in sports_2 %}
<!-- Blah blah -->
{% endfor %}
</div>
I recommend using Django filters.
Django snippets provides a partitioning template filter, which you can use like:
{% load listutil %}
<div class="grid_8 alpha">
{% for sport in sports|partition:"2"|first %}
<!-- Blah Blah -->
{% endfor %}
</div>
<div class="grid_8 omega">
{% for sport in sports|partition:"2"|last %}
<!-- Blah Blah -->
{% endfor %}
</div>
This is the task of a rendering system, not view. The view should not know whether you will display 2, 3 or 4 columns in your template.
It is always better to use default Django tags.
Use default Django template tag cycle:
<table>
{% for item in items %}
{% cycle 'row' '' as row silent %}
{% if row %}<tr>{% endif %}
<td>
{{ item }}
</td>
{% if not row %}</tr>{% endif %}
{% endfor %}
</table>
It will display your list [1 2 3 4 5 6] as
1 2
3 4
5 6
By the way, Jinja2 template engine has batch and slice filters which will do the trick. I switched to jinja2 and now have none of those problems of "how to display x using poor django tags and filters"
I think you will have to make your own template tag to do splits on queries. I would do something like.
from django.template import Library, Node, TemplateSyntaxError
from restaurants.forms import MenuItemForm
class Split(Node):
def __init__(self, queryset, split_count=2, basename=None):
self.queryset_name = queryset
self.split_count = split_count
self.basename = basename if basename else queryset
def render(self, context):
qs = context[self.queryset_name]
qs_break = len(qs)/self.split_count
for x in xrange(0, self.split_count-1):
context["%s_%i"%(self.basename, x+1)] = qs[qs_break*x:qs_break*(x+1)]
context["%s_%i"%(self.basename, x+2)] = qs[qs_break*x+1:]
return ''
def split(parser, token):
"""
Call from template will be
{% split <queryset> on <count> as <name> %}
"""
tokens = token.split_contents()
if len(tokens) > 6:
raise TemplateSyntaxError("Too many Tokens")
#Do various tests to make sure it's right.
return Split(tokens[1], tokens[3], tokens[5])
split = register.tag(split)
Please note that I haven't actually tested this code, so it might fail spectacularly, but it should point you towards the right direction for getting that stuff out of your view.
Late response, pretty much 13 years later :) but I think the easiest way if you have a fixed length list is to follow the same approach you used in your example, just slice the list. But there's no need to slice on the view, you can slice on the template using the slice filter.
<div class="grid_8 alpha">
{% for sport in sports|slice:":7" %}
<!-- Blah blah -->
{% endfor %}
</div>
<div class="grid_8 omega">
{% for sport in sports|slice:"7:" %}
<!-- Blah blah -->
{% endfor %}
</div>
Note: If you don't have a fixed size list you will probably need to check out the length filter (sports|length) and find a way to divide in Django templates. But at that point is probably better to create your own filter following #notnoop response.
Here's a quick solution which uses bootstrap and needs no Django filters
<div class="row">
{% for sport in sports %}
<div class="col-md-6">
<!-- Blah Blah -->
</div>
{% endfor %}
</div>