I am still a learner for python django. I’d like to filter dynamically data on the table below
table
The informations in my html template are :
<table>
<thead>
<tr>
<th>N°Commande</th>
<th>Magasin</th>
<th>Objet</th>
<th>Date commande</th>
<th>Montant</th>
<th>Etat</th>
</tr>
</thead>
<tbody>
{% for item in query_results %}
<tr>
<td>{{ item.numero_commande }}</td>
<td>{{ item.enseigne}}</td>
<td>{{ item.Objet}}</td>
<td>{{ item.Date_commande}}</td>
<td>{{ item.Montant}}</td>
<td>{{ item.Etat}}</td>
</tr>
</tbody>
from the class : class Commande(models.Model)
Here is an exemple of what I’d like to have (filters on table fields) :
table with dynamic filters
thank you in advance for your help
Vinloup
There's a couple of routes you could take to accomplish this, but as a beginner I think you should take a look at the django-filter library. Setup is quite simple:
pip install django-filter
Then add 'django_filters' to your INSTALLED_APPS.
INSTALLED_APPS = [
...
'django_filters',
]
Then you create a FilterSet
import django_filters
class ProductFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='iexact')
class Meta:
model = Product
fields = ['price', 'release_date']
In your view you want somethign like this (for function based views)
def product_list(request):
f = ProductFilter(request.GET, queryset=Product.objects.all())
return render(request, 'my_app/template.html', {'filter': f})
And finally in your template you want something like this
...
<form method="get">
{{ filter.form.as_p }}
<input type="submit" />
</form>
<tbody>
{% for obj in filter.qs %}
<tr>
... render your table rows here using {{ obj }}
</tr>
{% endfor %}
</tbody>
...
You could also try different setups and the documentation on the library gives you a few examples.
You can filter dynamically the context in the view function that renders this page. So when you complete the form's fields, it makes a GET request to the server, the parameters that you need to filter the data are in this request. Then, you only need to filter the query with this parameters. Here you have the Django guide for make queries. Making queries | Django
I suggest you show the function code on your view.py file so we can understand how you are filtering the data.
You can filter the table with JavaScript and a input. If you are using Bootstrap:
https://www.w3schools.com/bootstrap/bootstrap_filters.asp
Template code with Bootstrap would look like this:
<input class="form-control" id="myInput" type="text" placeholder="Search..">
<table>
<thead>
<tr>
<th>N°Commande</th>
<th>Magasin</th>
<th>Objet</th>
<th>Date commande</th>
<th>Montant</th>
<th>Etat</th>
</tr>
</thead>
<tbody id="myTable">
{% for item in query_results %}
<tr>
<td>{{ item.numero_commande }}</td>
<td>{{ item.enseigne}}</td>
<td>{{ item.Objet}}</td>
<td>{{ item.Date_commande}}</td>
<td>{{ item.Montant}}</td>
<td>{{ item.Etat}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
$(document).ready(function(){
$("#myInput").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#myTable tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
</script>
Related
In views.py, I have the following function to render a PDF view:
def agent_render_pdf(request, *args, **kwargs):
pk = kwargs.get('pk')
agent = get_object_or_404(Agents, pk=pk)
invoices = Invoice.objects.filter(agent=agent)
invoice_total = invoices.aggregate(Sum('invoice_amount'))
template_path = 'agents/statement.html'
context = {'agent': agent,
'invoices':invoices,
'invoice_total': invoice_total,}
#Create a Django response object, and specify content_type as pdf
response = HttpResponse(content_type='application/pdf')
#if download:
#response['Content-Disposition'] = 'attachment'; filename"report.pdf"'
#if display:
response['Content-Disposition']='filename="report.pdf"'
#find the template and render it
template = get_template(template_path)
html = template.render(context)
#create a PDF
pisa_status = pisa.CreatePDF(
html, dest=response
)
if pisa_status.err:
return HttpResponse('We had some errors <pre>' +html +'</pre>')
return response
I am rendering that to 'statements.html' as follows:
<body>
{{ agent }}
<div class="table">
<table>
<th>Invoice Number</th>
<th>Invoice Date</th>
<th>Due Date</th>
<th>Invoice Amount</th>
<th>Invoice Age</th>
{% for i in invoices %}
<tr>
<td>{{ i.invoice_number }}</td>
<td>{{ i.invoice_date }}</td>
<td>{{ i.invoice_due_date|date:"m/d/Y" }}</td>
<td>{{ i.invoice_amount }}</td>
<td>{{ i.InvoiceAge }}</td>
</tr>
{% endfor %}
<tr>
<td> </td>
<td> </td>
<td>total:</td>
<td>${{ invoice_total }}</td>
<td> </td>
</tr>
</table>
</div>
My view is basically rendering as expected, accept that the invoice_total is showing up as
${'invoice_amount__sum':
Decimal('2500')}
instead of just proving the total of invoices as $2,500. I'm clearly getting the information I want, I just don't understand what I'm doing wrong that's causing the formatting issue?
The full PDF is:
Screen capture of PDF output
.aggregate() returns a dictionary, because you can get several aggregates at the same time (imagine selecting a count, a max, and a min at once, to avoid multiple queries)
So just set a key and use it:
invoice_total = invoices.aggregate(total=Sum('invoice_amount'))['total']
So I'm using django-simple-history for one of my projects. I'm using it on one of the models called "Address" to show the history of the records.
I've created a DetailView to show the information about the address and added context['history'] to show changes of the record. This works all fine.
I would be interested in what field changed, and I read the following; History Diffing
So I somehow need to loop through all the fields from the last two records and find the field which has changed...
I couldn't find any examples on how to achieve this so I tried adding the context to the view
#views.py
class Address(DetailView):
'''
Show details about the address
'''
model = Address
'''
Add history context to the view and show latest changed field
'''
def get_context_data(self, **kwargs):
context = super(Address, self).get_context_data(**kwargs)
qry = Address.history.filter(id=self.kwargs['pk'])
new_record = qry.first()
old_record = qry.first().prev_record
context['history'] = qry
context['history_delta'] = new_record.diff_against(old_record)
return context
And a simple model
#models.py
class Address(models.Model)
name = models.CharField(max_length=200)
street = models.CharField(max_length=200)
street_number = models.CharField(max_length=4)
city = models.CharField(max_length=200)
Template
#address_detail.html
<table>
<thead>
<tr>
<th scope="col">Timestamp</th>
<th scope="col">Note</th>
<th scope="col">Edited by</th>
</tr>
</thead>
<tbody>
{% for history in history %}
<tr>
<td>{{ history.history_date }}</td>
<td>{{ history.history_type }}</td>
<td>{{ history.history_user.first_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Somehow this doesn't feel right, there should be a way to iterate over the changes and only add the changed fields to the context...
Any ideas would be appreciated!
I have recently worked on this. I think you are missing a trick you have changes stored in history_delta. You can use this to show the changed fields.
Following will display tabulated result like which field was changed and what was the old and the new value of that field.
{% if history_delta %}
<h3>Following changes occurred:</h3>
<table>
<tr>
<th>Field</th>
<th>New</th>
<th>Old</th>
</tr>
{% for change in delta.changes %}
<tr>
<td>
<b>{{ change.field }}</b>
</td>
<td>
<b>{{ change.new }}</b>
</td>
<td>
<b>{{ change.old }}</b>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No recent changes found.</p>
{% endif %}
def ViewCharges(request):
account = get_object_or_404(StripeAccount, team_members=request.user)
payment_requests = PaymentRequest.objects.filter(company=account).order_by('-created')
return render(request, 'dashboard/charges.html',{'payment_requests':payment_requests})
This is how my template looks after doing
{% for request in payment_requests %}
<tr>
<td>{{ request.name }}</td>
<td>{{ request.email }}</td>
<td>{{ request.amount }}</td>
<td>{{ request.paid }}</td>
<td><a href="/dashboard/charges/{{ request.pk }}" class='btn btn-dark btn-sm'>Manage</a></td>
</tr>
{% endfor %}
And in my models, I store the paid field in pence (e.g 100 = £1), this is for stripe. And I can properly format it by doing
real_amount = "{:.2f}".format(amount / 100)
this works fine until I need to do it in a for loop in html, is there a way I can do this in the html doc
<tr>
<td>Bob</td>
<td>Bob#example.com</td>
<td>£20</td>
<td>Yes</td>
<td><a href="/dashboard/charges/3523" class='btn btn-dark btn-sm'>Manage</a></td>
</tr>
The rest is fine I just need some help with that formatting, does anybody have any suggestions?
Create a property on your models to calculate real_amount. Then you can access this property in your HTML template or anywhere else just like any other field attribute of your model.
Example:
class MyModel(...):
...
#property
def real_amount(self):
return "{:.2f}".format(self.amount / 100)
Then in your templates:
{{ request.real_amount }}
I got stuck. Problem I have is that I would like to create a list of objects.all() but where all objects, where one ForeignKey is the same, should be combined to one entry in a list.
My Model:
class TournamentStandings(models.Model):
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
player_place = models.FloatField(verbose_name=u"Place")
The list I would like to get is something like this:
ID | Player | Tournament| Place
1 | Name_1 | Tournament_1, Tournament_2| Place_on_tournament_1, P_o_t_2
2 |Name_2 |Tournament_1, Tournament_2| Place_on_tournament_1, P_o_t_2
So the ForeignKey(Player) would be the one I would like to limit and combine entries. I tried the generic view for objects.all() and the loop in my template:
{% for player in ranking_list %}
<tr>
<td>{{ ranking_list.id }}</td>
<td>{{ ranking_list.player }}</td>
<td>{{ ranking_list.tournament }}</td>
<td> {{ ranking_list.player_place }} </td>
</tr>
{% endfor %}
It didn't work. Any hints ??
Add an order_by to your query so that standings for the same player are sequential, and pass the result into itertools.groupby to get "sublists" (all standings for the same player grouped together). You can then process/format those in any way you like.
I used a little bit different aproach.
I used annotate in my views.py:
ranking_list = TournamentStandings.objects.values('player__name').annotate(Sum('player_points'))
return render(request, 'rankings.html', {'ranking_list': ranking_list})
Then in my template I show column with player__name and player_points_sum. Sorting is done by webstack_django_sorting in template so users can decide by wich column and what order they want the results are shown.
template.html:
{% load sorting_tags %}
<table class="table table-bordered">
<thead>
<tr>
<th>{% anchor player__name _("Gracz") %}</th>
<th>{% anchor player_points__sum _("Punkty") %}</th>
</tr>
</thead>
{% load static %}
<tbody>
{% autosort ranking_list %}
{% for ranking_list in ranking_list %}
<tr>
<td>{{ ranking_list.player__name }}</td>
<td> {{ ranking_list.player_points__sum }} </td>
</tr>
{% endfor %}
</tbody>
</table>
I need to display a table from my database using only certain columns. In my view I have this:
def home_page(request):
query_results = Model.objects.filter(open=True)
return render(request, 'home.html')
and my home.html page looks like this:
<table>
<tr>
<th>Column1</th>
<th>Column2</th>
</tr>
{% for item in query_results %}
<tr>
<td>{{ item.col1 }}</td>
<td>{{ item.col2 }}</td>
<tr>
{% endfor %}
</table>
However, when I go to the page, there isn't any data in the table. Am I going about this wrong?
Thanks for your help.
You forget to include query_results to the template context. Try this:
return render(request, 'home.html', {'query_results': query_results})