Django loop over list from view in html template - django

I'm asking how I can pick up a for loop in my django class based view to my HTML template.
User can check one or multiple checkboxe(s) and I would like to display informations for each checked checkboxes.
In my view I have :
checkbox_list = self.request.GET.getlist('PUBSDChoice') #Get object id checked by user
context_data['checkbox_list'] = checkbox_list
for checkbox in checkbox_list:
pubsd = Publication.objects.get(id=checkbox)
get_request = Download.objects.filter(pub__publication__id=pubsd.id).count()
context_data['pubsd'] = pubsd
context_data['get_request'] = get_request
Now, in my template I have :
<table>
<tbody>
<tr>
<th>{% trans 'Publication ID' %}</th>
<th>{% trans 'Requests' %}</th>
</tr>
{% for item in checkbox_list %} # I'm not sure for this loop
<tr>
<td>{{ pubsd.pub_id }}</td> #Do I have to add item.??
<td>{{ get_request }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Thank you very much
EDIT :
This is my real code with all querysets inside my view :
checkbox_list = self.request.GET.getlist('PUBSDChoice')
context_data['checkbox_list'] = checkbox_list
for checkbox in checkbox_list:
pubsd = Publication.objects.get(id=checkbox) # display publication id
# Count number of requests in download table for checked publication
get_request = Download.objects.filter(pub__publication__id=pubsd.id).count()
#Get sum of publication usage (= downloads) for checked publication
get_download = Download.objects.filter(pub__publication__id=pubsd.id).aggregate(get_sum_usage=Sum('usage'))
# Get country which maximum download the checked publication
get_country = Country.objects.filter(download__pub__publication__id=pubsd.id).annotate(
ndown=Count('download')).order_by('-ndown').first()
# Get customer which maximum download the checked publication
get_customer = Download.objects.filter(pub__publication__id=pubsd.id).values('email').order_by(
'email').annotate(count_email=Count('email')).first()
# Get the best downloaded format for the checked publication
get_format = Download.objects.filter(pub__publication__id=pubsd.id).values('pub__format').annotate(
format_count=Count('pub__format')).order_by('-format_count').first()
context_data['pubsd'] = pubsd
context_data['get_request'] = get_request
context_data['get_download'] = get_download
context_data['get_country'] = get_country
context_data['get_customer'] = get_customer['email']
context_data['get_format'] = get_format['pub__format']
And this is exactly my model :
class Publication(models.Model):
pub_id = models.CharField(max_length=10, verbose_name=_('publication ID'), default='')
title = models.CharField(max_length=512, verbose_name=_('publication title'), null=False, unique=True)
category = models.ForeignKey(Category, verbose_name=_('category'), null=False, related_name='publication')
nb_document = models.IntegerField(verbose_name=_('number of documents'), default=0)
nb_download = models.IntegerField(verbose_name=_('number of downloads'), default=0)
new_publication = models.BooleanField(verbose_name=_('new publication'), default=True)
class Document(models.Model):
language = models.CharField(max_length=2, verbose_name=_('language'), choices=LANGUAGE_CHOICES, null=False)
format = models.CharField(max_length=10, verbose_name=_('format'), choices=FORMAT_CHOICES, null=False)
title = models.CharField(max_length=512, verbose_name=_('document title'), null=False)
publication = models.ForeignKey(Publication, verbose_name=_('publication title'), null=False,
related_name='documents')
nb_download = models.IntegerField(verbose_name=_('number of downloads'), default=0)
class Download(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'), related_name='download')
pub = models.ForeignKey(Document, verbose_name=_('Publication ID'), null=False)
usage = models.IntegerField(verbose_name=_('usage'), default=0)
class Customer(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'))
institution = models.CharField(max_length=255, verbose_name=_('institution'), null=True)
As I said previously, for one checked publication it works fine, but when I want to check multiple publications, it does't work.
If someone could help me to convert this, it will be super ! Else I will try to use the good answer previously done to do that :)

Here you each time overwrite the previous value of the key. As a result in the final context_data contains only values extracted in the last iteration.
checkbox_list = self.request.GET.getlist('PUBSDChoice')
context_data['checkbox_list'] = checkbox_list
context_data['pubsd'] = Publication.objects.filter(
id__in=checkbox_list
).annotate(
ndown=Count('publication__download') # or something related
)
We thus filter the queryset such that it only contains Publications with the id in the list, and we annotate with the number of downloads (It is possible that the expression is a bit different, since you did not include the models.py).
The above will not be sorted according to the checkbox_list. If that is a requirement, you can post-sort it.
In the template, you can then render this with:
{% for item in pubsd %}
<tr>
<td>{{ item.pub_id }}</td>
<td>{{ item.ndown }}</td>
</tr>
{% endfor %}
We thus iterate over the pubsd queryset, and for each item (this is a Publication object), we render item.pub_id, and item.ndown.

Related

Get the first three human readable elements in a queryset

I'm trying to render elements in a Django view. Every clinic object has many specialities, but for estetic reasons I only want the first three of them to be displayed in the template. I've tried:
def clinics_index(request):
clinics = Clinic.objects.all()
for clinic in clinics:
speciality = clinic.get_speciality_display
context = {
'clinics' : clinics,
'speciality' : speciality,
}
return render(request, 'guide/clinic/clinic_directory.html', context)
This now renders the human-readable name of the speciality field (which is a multiple choice field in the model). However, I can't use substraction to only get 3 elements like here:
speciality = clinic.get_speciality_display[:3]
As I get the following error:
TypeError at /guide/clinics/
'method' object is not subscriptable
How can I render it?
Edit:
This is the Clinic model:
class Clinic(models.Model):
name = models.CharField(max_length=75, blank=True, null=True)
speciality = MultiSelectField(choices=Speciality.choices, max_length=100, blank=True, null=True)
city = models.CharField(max_length=20, choices=Cities.choices, blank=True, null=True)
ward = models.CharField(max_length=20, choices=Wards.choices, blank=True, null=True)
full_address = models.CharField(max_length=100, blank=True, null=True)
maps_link = models.CharField(max_length=75, blank=True, null=True)
train_access = models.CharField(max_length=50, blank=True, null=True)
bus_access = models.CharField(max_length=50, blank=True, null=True)
parking = models.CharField(_('Parking availability'), max_length=75, blank=True, null=True)
phone_number = models.CharField(max_length=20, blank=True, null=True)
english_support = models.BooleanField(default=False, blank=True, null=True)
holiday_availability = models.BooleanField(_('Availability on weekends/holidays'), default=False, blank=True, null=True)
slug = models.SlugField(blank=True, null=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('guide:clinic_detail', kwargs={"slug" : self.slug})
And the template snippet:
<tbody>
{% for clinic in clinics %}
<tr>
<td>{{clinic.name}}</td>
<td>{{clinic.city}}</td>
<td>{{clinic.ward}}</td>
<td>{{speciality}}</td>
<td>More...</td>
</tr>
{% endfor %}
</tbody>
EDIT:
This code is rendering the first 3 human readable elements as I wanted:
clinics = Clinic.objects.all()
for clinic in clinics:
speciality = ','.join(clinic.get_speciality_display().split(',')[:3])
However, I am struggling to render it correctly with its correspondant instance. This code:
fff = [{'name': i.name, 'speciality': ','.join(i.speciality[:3])} for i in Clinic.objects.all()]
Is rendering the non-human readable names. How could connect both (and also display city and ward fields for each instance)?
I assume that in a loop you want to collect all the data. To do this, you need to save them to a list. But that's overkill, just pass clinics to a dictionary and iterate over all the values in the template. Also, for links, I used clinic.slug instead of clinic.get_absolute_url, since the model already returns the generated url through the get_absolute_url method.
views.py
def clinics_index(request):
clinics = Clinic.objects.all()[:3]
return render(request, 'guide/clinic/clinic_directory.html', {'context': clinics})
templates
{% for clinic in context %}
<p>{{ clinic }}</p>
<tr>
<td>{{ clinic.name }}</td>
<td>{{ clinic.city }}</td>
<td>{{ clinic.ward }}</td>
<td>{{ clinic.speciality }}</td>
<td>More...</td>
</tr>
{% endfor %}
</tbody>
Update 05.11.2022
To get the clinic.get_speciality_display() value, you need to call the method using parentheses. When I print out the value type, I get a string. Therefore, in order to take the first three elements, I turn the string into a list, select the desired number and again turn it into a string.
So you can select the first three records:
clinics = Clinic.objects.all()
for clinic in clinics:
speciality = ','.join(clinic.get_speciality_display().split(',')[:3])
all code:
views.py
def clinics_index(request):
#fff = [{'name': i.name, 'speciality': i.speciality[:3]} for i in Clinic.objects.all()]#if you need to display 'speciality' as a list
fff = [{'name': i.name, 'speciality': ','.join(i.speciality[:3])} for i in Clinic.objects.all()]
return render(request, 'guide/clinic/clinic_directory.html', {'context': fff})
templates
<tbody>
{% for a in context %}
<tr>
<p><td>{{ a.name }}</td></p>
<p><td>{{ a.speciality }}</td></p>
</tr>
{% endfor %}
</tbody>
If that's not what you need. Show what the data looks like and what you want to see.

Django can't display data from two models

I am trying to display data from two different models. The two models have a one-to-many relationship but I am not sure why it is not displaying the data from the MembersPresent model. Here are my models
and view
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
def __str__(self):
return self.mode_of_meeting
class MembersPresent(models.Model):
flyminute = models.ForeignKey(fly_minute, on_delete=models.CASCADE)
name = models.CharField(max_length=25)
status = models.CharField(max_length=25)
email = models.EmailField(max_length=25)
phone = models.IntegerField()
def __str__(self):
return self.name
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id)
return render(request, 'minute_report.html', locals())
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.flyminute.name}}</td>
<td>{{rpt.flyminute.status}}</td>
<td>{{rpt.flyminute.email}}</td>
<td>{{rpt.flyminute.phone}}</td>
</tbody>
{%endfor%}
You need to use 'prefetch_related()'
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
This has a similar purpose to select_related, in that both are designed to stop the deluge of database queries that is caused by accessing related objects, but the strategy is quite different.
models.py
class MembersPresent(models.Model):
flyminute = models.ForeignKey(
fly_minute,
related_name='memberspresent_set', # this will be the default name, incase of need of change provide a new one
on_delete=models.CASCADE
)
...
views.py
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id).prefetch_related('memberpresent_set')
return render(request, 'minute_report.html', locals())
For further control, you can use Prefetch along with prefetch_related()
Note:
locals() returns a dict of all the locally defined variables in the current scope and this may result in exposing sensitive info. Instead of that create a custom dict and return it.
...
context = {
'report': report,
...
}
return render(request, 'minute_report.html', context)
You are referencing and querying in the opposite way. Your fly_minute model doesn't contain MembersPresent model as the Foreign Key. You are filtering the fly_minute model and trying to access MembersPresent model. So, you should change your fly_minute to in this way:
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
member = models.ForeignKey(MembersPresent, on_delete=models.CASCADE)#add this line and remove fly_minute in MembersPresent model
def __str__(self):
return self.mode_of_meeting
Then in template file change it to in this way:
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.member.name}}</td>
<td>{{rpt.member.status}}</td>
<td>{{rpt.member.email}}</td>
<td>{{rpt.member.phone}}</td>
</tbody>
{%endfor%}
I guess it works
Thanks, I ended up using fetch-related and had to make adjustments to my template.
<tr>
<th>Name</th>
<th>Status</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
{%for rpt in report%}
{%for rpts in rpt.memberspresent_set.all%}
<tbody>
<tr class="table-active">
<td>{{rpts.name}}</td>
<td>{{rpts.status}}</td>
<td>{{rpts.email}}</td>
<td>{{rpts.phone}}</td>
</tbody>
{%endfor%}
{%endfor%}

How to get total pv created for all of User's Django

I have a simple models:
class Pv(models.Model):
accounts =(
('Sub CF','Sub CF'),
('Special','Special'),
('Directors','Directors'),
('Operations','Operations'),
('LSGDP','LSGDP'),
('DWAP','DWAP'),
('Capacity(USD)','Capacity(USD)')
)
acc =(
('Yes','Yes'),
('No', 'No')
)
source =(
('GOG','GOG'),
('Others', 'Others')
)
pv =(
('General','General'),
('Honorarium','Honorarium')
)
center=(
('Cost Center 1','Cost Center 1'),
('Cost Center 2','Cost Center 2'),
('Cost Center 3','Cost Center 3'),
('Cost Center 4','Cost Center 4'),
('Cost Center 5','Cost Center 5')
)
stat =(
('Completed','Completed'),
('Returned','Returned'),
('Cancelled','Cancelled')
)
IA_System_Code = models.AutoField(primary_key = True)
IA_code = models.CharField(max_length = 150)
Date_recieved = models.DateField()
Pv_reference = models.CharField(unique = True, max_length = 120)
Source_of_Funding = models.CharField(max_length=50, choices = source)
Cost_center = models.CharField(max_length=50, choices = center)
Payee = models.CharField(max_length=500)
Description = models.CharField(max_length = 500)
Account_code = models.CharField(max_length=350)
Gross_amount = models.DecimalField(max_digits=19, decimal_places=2)
Withholding_tax = models.DecimalField(max_digits=19, decimal_places=2)
Net_amount = models.DecimalField(max_digits=19, decimal_places=2)
Status = models.CharField(max_length = 60, choices = stat )
Remarks =models.CharField(max_length = 500, blank = True)
Acc_Impress = models.CharField(max_length = 350,choices=acc)
Date_returned =models.DateField(null=True,blank = True)
Type_of_accounts= models.CharField(max_length = 100, choices = accounts)
Type_of_pv = models.CharField(max_length = 20, choices = pv)
returned_to_chest = models.DecimalField(max_digits=19, decimal_places=2)
created = models.DateTimeField(null=True)
created_by = models.ForeignKey('auth.User', blank=True, null=True,\
default=None,on_delete=models.CASCADE,related_name='create')
modified = models.DateTimeField(null=True)
modified_by = models.ForeignKey('auth.User', blank=True, null=True,\
default=None ,on_delete=models.CASCADE,related_name='modified')
class Meta():
ordering = ["IA_System_Code"]
def __str__(self):
return self.Description
def save(self, *args, **kwargs):
user = get_current_user()
if user and not user.pk:
user = None
if not self.pk:
self.created_by = user
self.created = datetime.now()
else:
self.modified_by = user
self.modified = datetime.now()
super(Pv, self).save(*args, **kwargs)
I'm struggling to figure out, what I think should be a simple query, with Django's ORM.
Let's say I have a total of 6 PV created by 3 unique Users Now, what I really want is to query all pv and count the pvs created by each User, but only want one of each unique User and add a (what I think should be an annotated) property called total to each User. i dont also want to display users in the system who have not made any pv entry.
So if the User has 2 PV created , his total will be 2. please can anybody help me out .
How do i display it on my template as a table.
example :
user total pv recorded for the yr
John 10
peter 20
pack 5
please can anyone help me out . looks like i dont know what am doing. thank u
You can write this query.
views.py
from django.db.models import Count, Q # import Q here
import datetime
today = datetime.datetime.now()
qry = User.objects.filter(Q(create__isnull=False) & Q(create__created__year=today.year)).\
annotate(counter=Count('create')).\
prefetch_related('create') # this will only count the PV s from current yaer
send qry in template
template
{% for i in qry %}
{% if i.counter != 0 %} # checking if PV exist for user
# edited line
<p>{{ i.first_name }} {{ i.counter }}</p> # first name number of PVs
{% endif %}
{% endfor %}
I hope this helps.
Edit
You can print anything you want. {{ j.description }} is for example. I have edited the code. Current code will print fisrt_name and counte (john 5). you can replace first_name with any like first_name last_name count, or you have defined name in model.
Edited
i edited your query so it's now counting only those users who have only registered a pv. now i need reset the counter to zero when ever a new year start
#sandeep your query was not displaying anything on the template so i first queried out all the users
VIew.py
from django.db.models import Count, Q
import datetime
qry = User.objects.all()
i then filtered the query with your code
qryr = qry.filter(Q(create__isnull=False)\ &
Q(create__created__year=today.year))\
.annotate(counter=Count('create'))\
.prefetch_related('create').order_by('-counter')
and here is my template
template.html
<table class="table table-bordered table-hover">
<thead>
<tr>
<th scope="col">Users</th>
<th scope="col">Pv's Recorded</th>
</tr>
</thead>
<tbody>
{% for i in qryr %}
<tr>
<td>{{i.first_name}} {{i.last_name}}</td>
<td> {{ i.counter }}</td>
</tr>
{% endfor %}
</tbody>
</table>
thank you very much

Django printing many to many children not in same order as input

I have a Tourguide model with a many to many relationship with Places. Both models are defined as :
class Tourguide(models.Model):
id = models.AutoField(db_column='ID', primary_key=True, unique=True)
title = models.CharField(db_column='Title', max_length=255, blank=True)
places = models.ManyToManyField(Place, db_column='placesdj')
places_app = models.CharField(max_length=255, db_column='places')
created_on = models.DateTimeField(db_column='Created_On', default = now)
class Meta:
managed = False
db_table = 'tourguide'
def __str__(self):
return self.title
class Place(models.Model):
place_id = models.AutoField(db_column='ID', primary_key=True)
place_name = models.CharField(db_column='Place_Name', max_length=255)
address_line_1 = models.CharField(db_column='Address_Line_1', max_length=255)
address_line_2 = models.CharField(db_column='Address_Line_2', max_length=255)
area = models.CharField(db_column='Area', max_length=255)
class Meta:
managed = False
db_table = 'Place'
def __str__(self):
return self.place_name
THE PROBLEM
When I try to print the places in a tourguide using :
{% for place in tour.places.all %}
<tbody>
<td>{{ forloop.counter }}</td>
<td>id: {{place.place_id}}, {{ place.place_name }} </td>
<td> {{ place.description }} </td>
</tbody>
{% endfor %}
The order of the places is all random and not the same as the order I inputed it as. I want to print the places in the same order that I placed them in. My view for listing the tourguides and places within them is as so.
def tour_list(request, template_name='tourguides/tour_list.html'):
tourguide_list = Tourguide.objects.all()
paginator = Paginator(tourguide_list,6)
page = request.GET.get('page')
tourguides = paginator.get_page(page)
data = {}
data['tourguides'] = tourguides
return render(request, template_name, data)
Update
I have an array of place id's in the tourguide table, is there a way i can use that?
Relational databases do not sort rows by default, and since they are internally stored in all kinds of weird data structures, there is no "input order" either.
As a workaround, you can use the automatically generated place_id field as a sort key as it is pretty much guaranteed to go up as new entries are created. You can add a default sorting to your Place class, for example:
class Place(models.Model):
...
class Meta:
...
ordering = ('place_id',)
That would guarantee that any queries that will return a Place queryset will be ordered by place_id by default (i.e. unless you have an explicit .order_by() clause).

Only show object once and count it

after searching for a long time without getting an answer i'm gonna try here.
I'm working on django. My project is a mailling system, each time a recipient open a mail i know what mail get opened who opened it and when it get opened.
Here is the table where i display the stats. It shows me every recipient and the datetime, but my problem is that i want to see every recipient once, and then to show how many times it get opened.
<tbody>
{% for stat_mail in stat_mail %}
{% ifchanged stat_mail.recipient %}
<tr>
<td>{{ stat_mail.recipient }}</td>
<td>{{ stat_mail.datetime }}</td>
<td>{{ stat_mail.recipient_set.all|length }}</td>
</tr>
{% endifchanged %}
{% endfor %}
</tbody>
For example :
Test 1 opened the mail at 5PM and at 8PM, so the table should display
Test 1 / 5PM, 8PM / 2
The name of the recipient, the date of the oppening, and the number of oppening.
Sorry for the bad english but i'm french :)
Hope someone can help me, if u have other question or need more code just ask.
Thanks a lot !
EDIT : My models.py
class Recipient(models.Model):
name = models.CharField(max_length=255, verbose_name= ('Nom'), null=True, blank=True)
first_name = models.CharField(max_length=255, verbose_name= ('Prénom'), null=True, blank=True)
mail = models.EmailField(verbose_name= ('Adresse du destinataire'))
def __unicode__(self):
return u'%s %s' % (self.name, self.first_name)
class Tag(models.Model):
name = models.CharField(max_length=255, blank=False)
recipients = models.ManyToManyField(Recipient, verbose_name='Destinataires', null=False, blank=False, related_name="tags")
def __unicode__(self):
return self.name
class Mail(models.Model):
subject = models.CharField(max_length=255, verbose_name= ('Sujet'), blank=False, null=False)
content = HTMLField(verbose_name= ('Contenu'), blank=False, null=False, default=' ')
tags = models.ManyToManyField(Tag, verbose_name= ('Destinataires'), null=True, blank=True, related_name='mails')
recipients = models.ManyToManyField(Recipient, verbose_name='Destinataires', null=True, blank=True, related_name='mails')
date_create = models.DateTimeField(verbose_name= ('Date de création'), default=datetime.now, blank=False, editable = False)
writer = models.ForeignKey(Intervenant, verbose_name= ('Personne écrivant la compagne'), null=True, blank=True)
holding = models.ForeignKey(Holding, verbose_name= ('Organisation'),related_name= ('Questionnaire_mail'), null=False, blank=False, default=1, editable = False)
sended = models.BooleanField(verbose_name = ('Compagne envoyée ?'), default=False, editable=False)
opened = models.IntegerField(verbose_name=("Nombre totale d'ouverture"), default=0, editable=False)
email = models.EmailField(verbose_name='Destinataire de Test', blank=True, null=True)
date_create = models.DateTimeField(verbose_name= ('Date de création'), default=datetime.now, blank=False, editable = False)
date_sent = models.DateTimeField(verbose_name= ('Date de création'), blank=True, null=True, editable = False)
def __unicode__(self):
return self.subject
class Mail_Stats(models.Model):
mail = models.ForeignKey(Mail, verbose_name= ('Compagne'), related_name='mails_stats')
recipient = models.ForeignKey(Recipient, verbose_name= ('Destinataires'), null=True, blank=True, related_name='mails_stats')
datetime = models.DateTimeField(verbose_name= ('Date et Heure'), auto_now_add=True)
You should prepare your data in the view and then pass it to the template. Something like this (untested):
from django.shortcuts import render
from .models import Mail_Stats
def stats_view(request):
recipient_list = [] # this will be put in the template context
current_recipient = None
cnt_read = 0
read_datetime_list = []
for stat in Mail_Stats.objects.all().order_by('mail', 'recipient'):
if stat.recipient != current_recipient:
if cnt_read > 0:
recipient_list.append({
'recipient': current_recipient,
'read_datetime_list': read_datetime_list,
'cnt_read': cnt_read
})
current_recipient = stat.recipient
cnt_read = 0
read_datetime_list = []
cnt_read += 1
read_datetime_list.append(stat.datetime)
# add last recipient to the list, if not None
if current_recipient is not None:
recipient_list.append({
'recipient': current_recipient,
'read_datetime_list': read_datetime_list,
'cnt_read': cnt_read
})
render(request, 'mail_stats.html', { 'recipient_list': recipient_list })
Then in your template you could simply do something like this:
<tbody>
{% for r in recipient_list %}
<tr>
<td>{{ r.recipient }}</td>
<td>
<ul>
{% for dt in r.read_datetime_list %}
<li>{{ dt }}</li>
{% endfor %}
</ul>
</td>
<td>{{ r.cnt_read }}</td>
</tr>
{% endfor %}
</tbody>
The important thing is: do not struggle doing complex stuff in templates, keep them only for presentation purposes. Move all logic in the view (or models, or utility modules), there you can leverage all the power of Python.