How to create a pagination for a dataframe? - python

I want to create a pagination system for my dataframe. I always create pagination with my queries but It doesn't work in dataframe. I cannot display on my template.
This is my views.py
def get_context_data(self, **kwargs):
...
df = pd.DataFrame(list(Case.objects.all().values(...)))
query = df.assign(cnt=1).groupby([...)['cnt'].sum().reset_index()
paginator = Paginator(query, 10)
page_number = self.request.GET.get('page')
if page_number == None:
page_number = 1
page_obj = paginator.page(int(page_number))
print(page_obj) ----> <Page 1 of 33>
context['query'] = query
return context
And this is my template
<table class="table table-bordered" >
<tbody>
{% for index, row in query.iterrows %}
<tr>
{% for cell in row %}
<td>
{{cell}}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Table shows nothing. How can I solve that?

Related

Django-filter: count data

Does anybody knows how can I use count based on selected value using django_filters
Error
'UserFilter' object has no attribute 'count'
My Reference link
views.py
def search(request):
user_list = Person.objects.all()
user_filter = UserFilter(request.GET, queryset=user_list)
count = user_filter.count() #this will return an error
print(count)
return render(request, 'user_list.html', {'filter': user_filter})
filters.py
from django.contrib.auth.models import User
from .models import Person
import django_filters
class UserFilter(django_filters.FilterSet):
class Meta:
model = Person
fields = ['category', 'firstname', 'lastname' ]
user_list.html
{% extends 'base.html' %}
{% block content %}
<form method="get">
{{filter.form.as_p}}
<button type="submit" >Search</button>
</form>
<table class="table table-bordered">
<thead>
<tr>
<th>Firstname</th>
<th> Lastname</th>
<th>Caegory</th>
</tr>
</thead>
<tbody>
{% for user in filter.qs %}
<tr>
<td>{{ user.firstname }}</td>
<td>{{ user.lastname }}</td>
<td>{{ user.category }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5">No data</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
I want to count all the list base from data I filtered
You'll want the count of the resulting queryset, which you can get from the filter's qs property (as you do in your template!).
Change
count = user_filter.count()
to
count = user_filter.qs.count()
You can work with the .qs attribute:
def search(request):
user_list = Person.objects.all()
user_filter = UserFilter(request.GET, queryset=user_list)
count = user_filter.qs.count()
return render(request, 'user_list.html', {'filter': user_filter})
.qs [GitHub] is a property that generates a QuerySet by filtering the original queryset by values in the fields of the FilterSet.

TypeError: 'Store' object is not iterable

I want to search title with database record. Database record may contain sub-string in many cell which i want to search. I want to render all the records but could not shows because "TypeError: 'Store' object is not iterable" occurs.
My application.py is:
def bookresult():
isbn = request.form.get("isbn")
title = request.form.get("title")
author = request.form.get("author")
year = request.form.get("year")
submit = []
session = Session()
result = session.query(Store).all()
for result in result:
if title in result.title:
return render_template("bookresult.html",results=result)
return render_template("login.html", message="Not found")
session.commit()
And my bookresult.html is:
{% block body %}
<h1> Search result book </h1>
<table>
<tr>
<th> ISBN number </th>
<th> Book title </th>
<th> Author name </th>
<th> Publish year </th>
</tr>
<tr>
{% for result in results %}
<td> {{ result.isbn }} </td>
<td> {{ result.title }} </td>
<td> {{ result.author }} </td>
<td> {{ result.year }} </td>
{% endfor %}
</tr>
</table>
{% endblock %}
Above code works if for loop in html file is removed. But how to get all the records without making iteration in html file.
How to get records iteratively in html file if my search string matched with database cell ?
Issue occurs in
a) if .. is .. True syntax
b) rendering in templates doesn't iterate over and over. You have to pass at once.
c) {% for i in range(count) %} will cause iteration for int object i.e we can access elements of list as list[i] only.
Now application.py will look like:
#app.route("/bookresult", methods=['POST'])
def bookresult():
isbn = request.form.get("isbn")
title = request.form.get("title")
author = request.form.get("author")
year = request.form.get("year")
session = Session()
list1 = []
list2 = []
list3 = []
list4 = []
results = session.query(Store).all()
# return render_template("message.html",result=type(results))
for i in results:
if (title in i.title) is True:
list1.append(i.isbn)
list2.append(i.title)
list3.append(i.author)
list4.append(i.year)
# counter = counter + 1
# else:
# counter = counter + 1
# if (title in i) is True:
# return render_template("bookresult.html",results=i)
# counter = counter + 1
# else:
# counter = counter + 1
# return render_template("bookresult.html", results=list1, list2, list3, list4)
return render_template("bookresult.html", count=len(list1), result1=list1, result2=list2, result3= list3, result4= list4)
session.commit()
And bookresult.html will be:
{% for i in range(count) %}
<tr>
<td> {{ result1[i] }} </td>
<td> {{ result2[i] }} </td>
<td> {{ result3[i] }} </td>
<td> {{ result4[i] }} </td>
</tr>
{% endfor %}

Optimize code in Django - view ManyToMany as matrix

I'm trying to show user group permissions in Django and show them in a "Drupal" style like a matrix. It works, but it takes too long to make the query and paint it in the template. Is there some way to improve my code?
view img
up(accomplished),down(views and template.html)
views :
def GroupPermissionsView(request):
title = "Groups Permissions"
groups = Group.objects.all()
permissions = Permission.objects.all()
context = Context({
'title': title,
'groups': groups,
'permissions': permissions,
})
return render(
request,
'forms_permissions.html',
context
)
template:
<table class="table table-striped table-inverse table-responsive table-bordered">
<thead>
<tr>
<th>Permission</th>
{% for group in groups %}
<th>{{ group.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for permission in permissions %}
<tr>
<td><b>{{permission.name}}<b></td>
{% for group in groups %}
{% if permission in group.permissions.all %}
<td><input type="checkbox" name="" checked="checked"></input></td>
{% else %}
<td><input type="checkbox" ></input></td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Your problem was that you run more than 4 * 200 queries, one query for every combination or rows and columns (permissions and groups). It is useful to get them all by one query. It is however not easy because the intermediate model of ManyToMany relationship between Permission and Group models is not explicit in django.contrib.auth.models. You can get that model by Model._meta API:
>>> GroupPermissions = Permission._meta.get_field('group').through
>>> GroupPermissions
<class 'django.contrib.auth.models.Group_permissions'>
>>> GroupPermissions._meta.db_table # the table that you use in the raw query
'auth_group_permissions'
Put it all together. Prefer a longer view and simple template:
update the view:
from collections import OrderedDict
GroupPermissions = Permission._meta.get_field('group').through
groups = Group.objects.all()
permissions = Permission.objects.all()
permission_group_set = set()
for x in GroupPermissions.objects.all():
permission_group_set.add((x.permission_id, x.group_id))
# row title and cells for every permission
permission_group_table = OrderedDict([
(permission, [(permission.id, group.id) in permission_group_set for group in groups])
for permission in permissions
])
context = Context({
'title': title,
'groups': groups,
'permission_group_table': permission_group_table,
})
update the template
{% for permission, cells in permission_group_table.items %}
<tr><td><b>{{permission.name}}<b></td>
{% for cell in cells %}
{% if cell %}
<td><input type="checkbox" name="" checked="checked"></input></td>
{% else %}
<td><input type="checkbox" ></input></td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}

Want to display rating stars in django

I am in new in django and i have a model "album" which has 3 fileds title , genre and rating and i am displaying them i a table and i want to display the digit"0" as many time as album.rating and i am using for loop from 0 to album.rating but it is displaying only once i.e if the album.rating is 2 then "0" should display only 2 times but in my case it is displaying only 1 time .Please help me.Thanks in advance.
Here is the code of the html -
{% if albums %}
{% for album in albums %}
<tbody>
<tr>
<td>{{ album.album_title }}</td>
<td>{{ album.genre }}</td>
<!-- rating stars -->
<td>
{% for i in album.rating %}
<option value={{i}}>0</option>
{% endfor %}
</td>
<td>
Edit
</td>
<td>
</td>
</tr>
</tbody>
Here is the code of view.py
def index(request):
if not request.user.is_authenticated():
return render(request, 'music/login.html')
else:
albums = Album.objects.filter(user=request.user)
paginator = Paginator(albums, 2) # Show 25 contacts per
page = request.GET.get('page')
try:
albums = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
albums = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
albums = paginator.page(paginator.num_pages)
song_results = Song.objects.all()
query = request.GET.get("q")
if query:
albums = albums.filter(
Q(album_title__icontains=query) |
Q(artist__icontains=query)
).distinct()
song_results = song_results.filter(
Q(song_title__icontains=query)
).distinct()
return render(request, 'music/index.html', {
'albums': albums,
'songs': song_results,
})
else:
return render(request, 'music/index.html', {'albums': albums})
Since you could not get the way to implement, after explaining:
{% for i in album.rating %} is like {% for i in 2 %} in your case, which turns out that, for a single digit, it's going to loop once. use range filter or so on.
I can suggest the quickest way to get it implemented via the answer: Check this
{% if albums %}
{% for album in albums %}
<tbody>
<tr>
<td>{{ album.album_title }}</td>
<td>{{ album.genre }}</td>
<!-- rating stars -->
<td>
{% with ''|center:album.rating as range %}
{% for i in range %}
<option value={{i}}>0</option>
{% endfor %}
{% endfor %}
</td>
<td>Edit</td>
<td></td>
</tr>
</tbody>
{% endif %}
Humble opinion, please look into DJango template filters and try and check
this.
P.S: have not evaluated the solution

Django-tables2 render merged tables

I use django-tables2 and have following table, which is populated by generated dictionary:
class SimpleStatTable(tables.Table):
Metric = tables.Column(accessor='metric')
Qty = tables.Column(accessor='qty')
Min = tables.Column(accessor='min')
Avg = tables.Column(accessor='avg')
Max = tables.Column(accessor='max')
def __init__(self, data, label=None, **kwargs):
self.label = label
super(SimpleStatTable, self).__init__(data, **kwargs)
class Meta:
order_by = ('Metric',)
empty_text = 'No data presented'
I want to render merged table of a few SimpleStatTable tables. Is it possible with django-tables2? I like django-tables2 features, such as sorting
I have a small example of desired tables.
I suppose i need to generate class for merged table dynamically like here, but how can i add additional merged column?
I have a solution, but it's not elegant.
I merge two dictionaries and build table for merged dictionary. After that i just add merged columns to the table. They are in same order as in merged dictionary. Also I've changed template for the table for handling merged columns.
Here is the code:
from collections import defaultdict
import django_tables2 as tables
def merge_table_dicts(labels, tables, key_column):
merged_tables = []
for table, label in zip(tables, labels):
new_table = []
for row in table:
new_row = {}
for key, value in row.iteritems():
if key == key_column:
new_row[key] = value
else:
new_row[old_key + '_' + label] = value
new_table.append(new_row)
merged_tables.append(new_table)
d = defaultdict(dict)
for l in merged_tables:
for elem in l:
d[elem[key_column]].update(elem)
merged_table_dicts = d.values()
return merged_table_dicts
def get_merged_table(labels, tables_dicts, key_column_name, merged_columns_order):
attrs = {}
# General options
class Meta:
order_by = (key_column_name,)
template = '_merged_table.html'
empty_text = 'No data presented'
attrs['Meta'] = Meta
attrs[key_column_name] = tables.Column()
for column in merged_columns_order:
for label in labels:
attrs[get_merged_key(column, label)] = tables.Column(verbose_name=label)
merged_table = type('MergedTable', (tables.Table,), attrs)
merged_columns = []
for merged_column_name in merged_columns_order:
column = tables.Column(verbose_name=merged_column_name,
attrs={"th": {"rowspan": len(labels)}})
merged_columns.append(column)
merged_table.merged_columns = merged_columns
# Merge data for table
data = merge_table_dicts(labels, tables_dicts, key_column_name)
return merged_table(data)
And it's a changed part of a template:
<thead>
<tr>
{% with column=table.columns|first %}
{% if column.orderable %}
<th rowspan="2" {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% else %}
<th rowspan="2" {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% endif %}
{% endwith %}
{% for column in table.merged_columns %}
<th colspan="{{ column.attrs.th.rowspan }}">{{ column.header }}</th>
{% endfor %}
</tr>
<tr>
{% for column in table.columns %}
{% if not forloop.first %}
{% if column.orderable %}
<td {{ column.attrs.th.as_html }}>{{ column.header }}</td>
{% else %}
<td {{ column.attrs.th.as_html }}>{{ column.header }}</td>
{% endif %}
{% endif %}
{% endfor %}
</tr>
</thead>

Categories

Resources