Update table html in django - python

I am new with Django and I am a little confused trying to update a HTML table populated from the database.
I need to update the table selecting different values from some drop-down list (year, month and provider_type).
This is my table.py:
import django_tables2 as tables
from .models import Proveedor, Estado
class ProveedorTable(tables.Table):
class Meta:
model = Proveedor
fields = ("id_provider", "name", "type", "year", "month")
sequence = ("id_provider", "name", "type", "year", "month")
My views.py
from django.shortcuts import render, render_to_response, RequestContext, HttpResponseRedirect
from django_tables2 import RequestConfig
from .tables import ProveedorTable
from .forms import ProvForm
from .forms import EstadoForm
from .models import Proveedor
from django.contrib import messages
def home(request):
table = ProveedorTable(Proveedor.objects.all())
RequestConfig(request).configure(table)
return render(request,'index.html',{'table': table})
My template index.html
{% load querystring from django_tables2 %}
{% load trans blocktrans from i18n %}
{% load bootstrap_toolkit %}
{% if table.page %}
<div class="table-container">
{% endif %}
{% block table %}
<table class="table table-striped table-condensed table-bordered"{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
{% block table.thead %}
<thead>
<tr>
{% for column in table.columns %}
{% if column.orderable %}
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% else %}
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% endif %}
{% endfor %}
</tr>
</thead>
{% endblock table.thead %}
{% block table.tbody %}
<tbody>
{% for row in table.page.object_list|default:table.rows %} {# support pagination #}
{% block table.tbody.row %}
<tr class="{% cycle "odd" "even" %}">
{% for column, cell in row.items %}
<td {{ column.attrs.td.as_html }}>{{ cell }}</td>
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</tbody>
{% endblock table.tbody %}
{% block table.tfoot %}
<tfoot></tfoot>
{% endblock table.tfoot %}
</table>
{% endblock table %}
{% if table.page %}
{% block pagination %}
<ul class="pagination">
{{ table.page|pagination }}
</ul>
{% endblock pagination %}
{% endif %}
I am confused if I need to use choicefield or an ajax function.
someone can bring me some snippet or a link where I can have a more clear process to implement this functionality
Thanks in advance

Here, <td {{ column.attrs.td.as_html }}>{{ cell }}</td> is where data is being used for displaying data. If you want to do a ajax request here, you have to do it in cell section. For example:
{% for column, cell in row.items %}
{% if column|stringformat:"s" == "some-string" %}
<td {{ column.attrs.td.as_html }} class="ajax-request">{{ cell }}</td>
<!-- or you can use:
<td {{ column.attrs.td.as_html }}><input class="ajax-request" value={{ cell }} type="button (or any other type)"></td>
for choice field, you need to render like
<td {{ column.attrs.td.as_html }}><select id=".ajax-request">
{% for items in cell.values %}
<option value={{ items }}></option>
</select></td>
-->
{% else %}
<td {{ column.attrs.td.as_html }} class="ajax-request">{{ cell }}</td>
{% endif %}
{% endfor %}
<script>
$(document).ready(function(){
$('.ajax-request').change(function(){
var e = document.getElementById("select_dropdown");
var value = e.options[e.selectedIndex].value;
$.ajax({
url: "your-url",
type: "post", // or "get"
data: value,
success: function(data) {
alert(data.result);
}});
});
</script>

Related

Django Form as a Table

The following code in the django template language is working but i don't know why. The purpose of this code is to display a form as a table with a number of columns. The first thing that throws me of is that the tag for opening a row is never giving but it is still made.
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% block content %}
<form method="get">
{% csrf_token %}
<table>
<tbody>
{% for field in filter.form %}
<td>{{ field.label}}</td>
<td>{{ field }}</td>
{% if forloop.counter|divisibleby:"4"%}
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<input type="submit" value="Search">
</form>
{% render_table table%}
{% endblock %}
This generates a four column table. Is there any way the opening tags can be explicitly declared?And why is this code working?
I have tried to explicitly create the tags for row explicitly but this didn't not create the table correctly.It had an empty row space and a extra row.
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% block content %}
<form method="get">
{% csrf_token %}
<table>
<tbody>
{% for field in filter.form %}
{% if forloop.counter|divisibleby:"5"%}
<tr>
{% endif %}
{% if forloop.counter|divisibleby:"5" == False %}
<td>{{ field.label}}</td>
<td>{{ field }}</td>
{% endif %}
{% if forloop.counter|divisibleby:"5"%}
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<input type="submit" value="Buscar">
</form>
{% render_table table%}
{% endblock %}
Why is this working? HTML is pretty lax and browsers can infer what you're trying to do with the context. td before a tr, there should be a row before -> add one
any way the opening tags can be explicitly declared? I believe with a combination of what you have and {% forloop.first %} + {% forloop.last %} this can be done.
Something along the lines of:
<table>
<tbody>
{% for field in filter.form %}
{% if forloop.first %}
<tr>
{% endif %}
<td>{{ field.label}}</td>
<td>{{ field }}</td>
{% if forloop.last %}
<tr>
{% elif forloop.counter|divisibleby:"4"%}
</tr>
<tr>
{% endif %}
{% endfor %}
</tbody>
</table>
Thanks I have put the following code which also works. I think it is now more deliberate. The first if creates the opening tag since the next tag should be a pair generated from the divisible these are in the elif the if contains the last tag which should be a closing tag alone since if it where a divisible pair of tags it would create a extra row.
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% block content %}
<form method="get">
{% csrf_token %}
<table>
<tbody>
{% for field in filter.form %}
{% if forloop.first %}
<tr>
{% endif %}
<td>{{ field.label}}</td>
<td>{{ field }}</td>
{% if forloop.last %}
</tr>
{% elif forloop.counter|divisibleby:"4"%}
</tr>
<tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<input type="submit" value="Buscar">
</form>
{% render_table table%}
{% endblock %}

Difference between IF in Python vs Template block? [duplicate]

Trying to use nested block and for loop in a Jinja template block setup.
{% block main %}
<table>
<tr>
<td>user id</td>
<td>user sec level</td>
</tr>
{% block main_nested_b scoped %}
{%
for user in list_users:
t_id_user = str(user[0][0])
t_sec_level = str(user[2][0])
%}
<tr>
<td>
<a href='/usersEdit?id_user={{ t_id_user }}' class='onwhite'>edit</a>
</td>
</tr>
{% endfor %}
{% endblock main_nested_b %}
{% endblock main %}
</table>
Error message:
jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 't_id_user'
Help?
You can't treat Jinja syntax as Python syntax. It's not the same thing. Keep your for tag separate from assignment (set) tags:
{% for user in list_users %}
{% set t_id_user = user[0][0] %}
{% set t_sec_level = user[2][0] %}
Note that there isn't even a : at the end of the for ... in ... syntax! Also you don't need to call str() here, leave that to Jinja to convert to strings for you; anywhere you use {{ t_id_user }} or {{ t_sec_level }} the value will be converted to a string anyway.
Here is the complete template:
<table>
{% block main %}
{% block main_nested_b scoped %}
{% for user in list_users %}
{% set t_id_user = user[0][0] %}
{% set t_sec_level = user[2][0] %}
<tr>
<td>
<a href='/usersEdit?id_user={{ t_id_user }}' class='onwhite'>edit</a>
</td>
</tr>
{% endfor %}
{% endblock main_nested_b %}
{% endblock main %}
</table>

Passing context to django admin index page

I'm trying to create a table on django admin's index page, listing all users registered in a specific timeframe. I've managed to already edit the index page to include my table but I now want to populate the table. I tried declaring the extra_context variable but it still doesn't pass it to the template. I've been on this issue for days and still can't figure out what I'm doing wrong. This is my admin.py file
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin
from .forms import SignUpForm, EditUserForm
from .models import CustomUser
from django.urls import path
from datetime import datetime, timedelta
from django.utils import timezone
class CustomUserAdmin(UserAdmin):
list_filter = ['created_at',]
list_display = ['username', 'email', 'created_at', 'is_active']
# index_template = 'admin/my_index.html'
def time_threshold(num):
num = int(num)
thresh = datetime.now(tz=timezone.utc) - timedelta(hours=num)
return thresh
print(time_threshold(30))
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path("user_metrics/", self.user_metrics),
]
return custom_urls + urls
def user_metrics(self, request, extra_context=None):
extra_context = extra_context or {}
user_24 = CustomUser.objects.filter(created_at__gt=time_threshold(730))
extra_context['users_in_past_24_hours'] = CustomUser.objects.filter(created_at__gt=time_threshold(24))
extra_context['users_in_past_week'] = CustomUser.objects.filter(created_at__gt=time_threshold(168))
extra_context['users_in_past_month'] = CustomUser.objects.filter(created_at__gt=time_threshold(730))
print(user_24)
return super(CustomUserAdmin, self).user_metrics(request, extra_context=extra_context)
admin.site.register(CustomUser, CustomUserAdmin)
admin.site.unregister(Group)
admin.site.site_header = "Savests Custom Admin"
And this is my index.html file I have inside template/admin folder
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}">{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block nav-sidebar %}{% endblock %}
{% block content %}
<div id="content-main">
{% include "admin/app_list.html" with app_list=app_list show_changelinks=True %}
</div>
<div>
<h5>Users in the last 24 hours</h5>
<table class="table table-hover table-bordered">
<caption>User Information</caption>
<thead class="thead-dark">
<th>User ID</th>
<th>Username</th>
<th>Email Address</th>
<th>Active Status</th>
<th>Staff Status</th>
</thead>
{% for a in users_in_past_24_hours %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.username }}</td>
<td>{{ a.email }}</td>
<td>
{% if a.is_active %}
<form action="{% url 'toggle_user_status_false' user_id=a.id %}" method="post">
{% csrf_token %}
<button class="btn btn-danger" type="submit">
Deactivate
</button>
</form>
{% else %}
<form action="{% url 'toggle_user_status_true' user_id=a.id %}" method="post">
{% csrf_token %}
<button class="btn btn-primary" type="submit">
Activate
</button>
</form>
{% endif %}
</td>
<td>
{% if a.is_staff %}
Staff
{% else %}
Not Staff
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br>
<hr>
<h5>Users in the past week</h5>
<table class="table table-hover table-bordered">
<caption>User Information</caption>
<thead class="thead-dark">
<th>User ID</th>
<th>Username</th>
<th>Email Address</th>
<th>Active Status</th>
<th>Staff Status</th>
</thead>
{% for a in users_in_past_week %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.username }}</td>
<td>{{ a.email }}</td>
<td>
{% if a.is_active %}
<form action="{% url 'toggle_user_status_false' user_id=a.id %}" method="post">
{% csrf_token %}
<button class="btn btn-danger" type="submit">
Deactivate
</button>
</form>
{% else %}
<form action="{% url 'toggle_user_status_true' user_id=a.id %}" method="post">
{% csrf_token %}
<button class="btn btn-primary" type="submit">
Activate
</button>
</form>
{% endif %}
</td>
<td>
{% if a.is_staff %}
Staff
{% else %}
Not Staff
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br>
<hr>
<h5>Users in the past month</h5>
<table class="table table-hover table-bordered">
<caption>User Information</caption>
<thead class="thead-dark">
<th>User ID</th>
<th>Username</th>
<th>Email Address</th>
<th>Active Status</th>
<th>Staff Status</th>
</thead>
{% for a in users_in_past_month %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.username }}</td>
<td>{{ a.email }}</td>
<td>
{% if a.is_active %}
<form action="{% url 'toggle_user_status_false' user_id=a.id %}" method="post">
{% csrf_token %}
<button class="btn btn-danger" type="submit">
Deactivate
</button>
</form>
{% else %}
<form action="{% url 'toggle_user_status_true' user_id=a.id %}" method="post">
{% csrf_token %}
<button class="btn btn-primary" type="submit">
Activate
</button>
</form>
{% endif %}
</td>
<td>
{% if a.is_staff %}
Staff
{% else %}
Not Staff
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br>
<hr>
</div>
{% endblock %}
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>{% translate 'Recent actions' %}</h2>
<h3>{% translate 'My actions' %}</h3>
{% load log %}
{% get_admin_log 10 as admin_log for_user user %}
{% if not admin_log %}
<p>{% translate 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
{% if entry.is_deletion or not entry.get_admin_url %}
{{ entry.object_repr }}
{% else %}
{{ entry.object_repr }}
{% endif %}
<br>
{% if entry.content_type %}
<span class="mini quiet">{% filter capfirst %}{{ entry.content_type.name }}{% endfilter %}</span>
{% else %}
<span class="mini quiet">{% translate 'Unknown content' %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
1st way is to declare subclass django.contrib.admin.site.AdminSite() and override the .index() method in admin.py
class MyAdminSite(django.contrib.admin.site.AdminSite):
def index(self, request, extra_context=None):
if extra_context is None:
extra_context = {}
user_24 = CustomUser.objects.filter(created_at__gt=time_threshold(730))
extra_context['users_in_past_24_hours'] = CustomUser.objects.filter(created_at__gt=time_threshold(24))
extra_context['users_in_past_week'] = CustomUser.objects.filter(created_at__gt=time_threshold(168))
extra_context['users_in_past_month'] = CustomUser.objects.filter(created_at__gt=time_threshold(730))
extra_context["app_list"] = get_app_list_in_custom_order()
return super(MyAdminSite, self).index(request, extra_context)
then you should register your site admin (also in admin.py)
my_admin_site = MyAdminSite(name='myadmin')
when you create your own AdminSite you need to register all models using it, so instead of
admin.site.register(YourModel) you should use my_admin_site.register(YourModel) for all models you use. you also need to add path to your adminsite in urls.py
from pathtoyouradmin.admin import my_admin_site
urlpatterns = [
...
path('admin/', my_admin_site.urls),
...
]
you can solve your problem other way. you can create contextprocessor where you check path of current page and if it admin index then provide needed extra_context
def context_users_info(request):
extra_context = {}
if request.path == 'index admin page'# you need to put path to your index admin page
user_24 = CustomUser.objects.filter(created_at__gt=time_threshold(730))
extra_context['users_in_past_24_hours'] = CustomUser.objects.filter(created_at__gt=time_threshold(24))
extra_context['users_in_past_week'] = CustomUser.objects.filter(created_at__gt=time_threshold(168))
extra_context['users_in_past_month'] = CustomUser.objects.filter(created_at__gt=time_threshold(730))
extra_context["app_list"] = get_app_list_in_custom_order()
return extra_context
and don't forget to register your context processor in settings.py

Can a child template also use a child template in django?

My child template path is project/sales/templates/sales/table.html.
It extends another child template sale_summary_change_list.html.
{% extends 'sales/sale_summary_change_list.html' %}
{% block result_list %}
<div class="results">
<table>
<thead>
<tr>
{% for header in table %}
<th>
<div class="text">
{{ header }}
</div>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in summary %}
<tr class="{% cycle 'row1' 'row2'}">
<td> {{ row.color_pref }} </td>
<td> {{ row.total | intcomma }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
The parent template is also located in the same folder. (project/sales/templates/sales/sale_summary_change_list.html)
{% extends 'admin/change_list.html' %}
{% load humanize %}
{% block content_title %}
<h1> Sales Summary </h1>
{% endblock %}
{% block result_list %}
{% block table %} {% endblock %}
{% endblock %}
{% block pagination %}{% endblock %}
My child template however is not appearing. What am I doing wrong?
You are doing things in wrong way. Just replace {% extends 'sale_summary_change_list.html' %} this block of code with this one {% extends 'sales/sale_summary_change_list.html' %}. It may work for you.

How do I remove the bottom bullet from django table

I generate the following table using django_table2
Semester Actual Prediction
Spring 2014 209 199
*1 coe
The semester, actual, and prediction are column names. My table is exactly how i need it. However, at the bottom of each table I always have the number of items in my model. I do not want that bullet. I know its default in django_table2. Is there a way to remove this? Below is another example:
Department Semester Actual Prediction
MIE 2014 Spring 202 210
MIE 2015 Fall 213 200
MIE 2015 Spring 11 12
*3 departments
The easiest way to do it (for me) is by creating this path (your_templates_dir/django_tables2/tables.html) on your templates directory with the following content:
{% spaceless %}
{% load django_tables2 %}
{% load i18n %}
{% if table.page %}
<div class="table-container">
{% endif %}
{% block table %}
<table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
{% nospaceless %}
{% block table.thead %}
<thead>
<tr>
{% for column in table.columns %}
{% if column.orderable %}
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% else %}
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% endif %}
{% endfor %}
</tr>
</thead>
{% endblock table.thead %}
{% block table.tbody %}
<tbody>
{% for row in table.page.object_list|default:table.rows %} {# support pagination #}
{% block table.tbody.row %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"even,odd" }}"> {# avoid cycle for Django 1.2-1.6 compatibility #}
{% for column, cell in row.items %}
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</tbody>
{% endblock table.tbody %}
{% block table.tfoot %}
<tfoot></tfoot>
{% endblock table.tfoot %}
{% endnospaceless %}
</table>
{% endblock table %}
{% if table.page %}
{% with table.page.paginator.count as total %}
{% with table.page.object_list|length as count %}
{% block pagination %}
<ul class="pagination">
{% if table.page.has_previous %}
{% nospaceless %}{% block pagination.previous %}<li class="previous">{% trans "Previous" %}</li>{% endblock pagination.previous %}{% endnospaceless %}
{% endif %}
{% if table.page.has_previous or table.page.has_next %}
{% nospaceless %}{% block pagination.current %}<li class="current">{% blocktrans with table.page.number as current and table.paginator.num_pages as total %}Page {{ current }} of {{ total }}{% endblocktrans %}</li>{% endblock pagination.current %}{% endnospaceless %}
{% endif %}
{% if table.page.has_next %}
{% nospaceless %}{% block pagination.next %}<li class="next">{% trans "Next" %}</li>{% endblock pagination.next %}{% endnospaceless %}
{% endif %}
</ul>
{% endblock pagination %}
{% endwith %}
{% endwith %}
</div>
{% endif %}
{% endspaceless %}
This approach will override all of the tables you create via django_table2 template tag and won't necessary work with upcoming versions of django_table2, but I'll be OK if you want to keep an specific version (in my case 0.15.0).
Another approach, which is more scalable, should work with future versions (and I recommend) is by subclassing Table, like described on the django-tables2 documentation.

Categories

Resources