How to build a table of objects without knowing their attributes? - django

I'm trying to build a table dynamically in my django template. I got the column names in my views.py and also got the contents of the table:
table = tenant_tables.models[table_name].objects.all()
headers = table.model._meta.get_fields(include_parents=True, include_hidden=False)
context = {'table': table, 'headers': headers}
return render(request, template_name=template_name, context=context)
Based on the received data, I want to build a table using a template, but I don't know how to sort through all the attributes of the object
<table
id="example"
class="table table-striped data-table"
style="width: 100%"
>
<thead>
<tr>
{% for header in headers %}
<th>{{header.verbose_name}}</th>>
{% endfor %}
</tr>
</thead>
<tbody>
{% for obj in table %}
<tr>
<td>{{obj}}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
{% for header in headers %}
<th>{{header.verbose_name}}</th>>
{% endfor %}
</tr>
</tfoot>
</table>
Can I implement this or should I create a view for each model in my application?

Yes, it's possible to implement this. But first you need to implement a custom filter which works like the getattr function in python.
Then you can do this:
...
<tbody>
{% for obj in table %}
<tr>
{% for header in headers %}
<td>{{ obj | getattr_filter:header }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
...
The filter should looks something like this:
#register.filter(name='getattr_filter')
def getattr_filter(obj, attribute):
return getattr(obj, attribute, None)
Check the docs for more details on how to implement a custom template filter.

Related

Dynamically update table when creating new enty using HTMX

After recent success in some simple HTMX tasks I wanted to extend adamchainz django-htmx example by a modal field that updates a table dynamically. I am not sure if I am returning the right thing in render ... but my problem is, the table is not being updated. Only when I hit reload.
view:
class CreateProductView(TemplateView):
template_name = "app/product_create.html"
form_class = OrderForm
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {'form': self.form_class()})
def post(self, request):
Product.objects.create(name = request.POST["name"], price = request.POST["price"])
part_template = "app/partial-rendering.html"
return render(request, part_template, {"base_template": "app/_partial.html"})
urls.py:
path("create/", views.CreateProductView.as_view(), name = 'create'),
This is my index.html with the table in it:
<div class="..."><button class="btn btn-primary"
id="showButton"
hx-get="/create"
hx-target="#modal-create">create</button</div>
<main role="main" id="main">{% include "app/orders_table.html" %}</main>
<div id="modal-create"></div>
I also have a partial-rendering.html in place:
{% extends base_template %}
{% block main %}
{% include "app/product_table.html" %}
{% endblock %}
and a _partial.html:
<main id="main">
{% block main %}{% endblock %}
</main>
I will not post the whole product_table.html here, I guess it is straight forward ... mainly:
<table class="table table-striped table-hover">
<thead>
<tr>
<th>product name</th>
<th>price</th>
</tr>
</thead>
<tbody>
{% for product in page.object_list %}
<tr>
<td>{{ product.name}}</td>
<td>{{ product.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>
The data from the form is collected via JS and sent to django using AJAX. I did not use the normal form submit because I wanted to avoid a page reload (which would solve that problem, I know).
I did try to put this together from the example mentioned above. Everything except the dynamic page update runs well!
Some approach is to remove the div targeted:
<div id="modal-create"></div>
then in your table body write the id deleted:
<tbody id="modal-create">
you want some partial for your table loops
{% for product in page.object_list %}
{% include 'some_table_body_tr_partial.html' %}
{% endfor %}
your partial might contain something like this:
<tr hx-target="this" hx-swap="outerHTML">
<td>{{ product.name}}</td>
<td>{{ product.price }}</td>
</tr>
This approach have an issue: the width of the form will take the wide of the first column.

How to render data from external database (Oracle) using datatables in Django Python?

I am retrieving data from a table in an external Oracle database and want to show data on web page using datatables. The retrieved data is in list form. Please suggest the way how to render list data in tabular form using datatables in Python Django.
Since I am connecting to external database and storing data in on single variable I am not able to find any solutions through standard models.py.
The code is not giving any error but empty table is being rendered on web page. My expectation is it should show desired data on web page in tabular form.
Please let me know of any other detail or code is required ?
#views.py
#Necessary imports
def show_data(request):
dsn_str = cx_Oracle.makedsn("<<HOSTNAME>>","<<PORT_NO>>","<<SCHEMA>>")
con = cx_Oracle.connect(user="user", password="***", dsn=dsn_str
, encoding='UTF-8')
cursor=con.cursor()
cursor.execute("select abc, pqr, xyz from myDB.myTable")
data_set=cursor.fetchall()
con.close()
return render(request, 'index.html', {"form":data_set})
#index.html
{% extends "base.html" %}
{% load static %}
{% block content %}
{% csrf_token %}
<div class="container">
<table id = "table" class= "table table-bordered">
<thead>
<tr>
<th>ABC</th>
<th>PQR</th>
<th>XYZ</th>
</tr>
</thead>
<tbody>
{% for data in form %}
<tr>
<td>{{ data.ABC }}</td>
<td>{{ data.PQR }}</td>
<td>{{ data.XYZ }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock content %}

Django Datatables view

Im trying to convert my tables in my django app to datatables using django-tables2.
Im my campaigns.py view I have:
class CampaignListView(FacebookAdInit):
""" CampaignListView for viewing all the campaigns"""
def get(self, request, *args, **kwargs):
ad_account = self.get_ad_account(kwargs.get('ad_account_id'))
campaigns = self.get_campaigns(ad_account.get('id')) \
if ad_account else None
context = {'campaigns': campaigns, 'ad_account': ad_account}
return render(request, 'app/campaigns/index.html', context)
Im my campaigns/index.html I have:
{% extends "app/empty_page.html" %}
{% load render_table from django_tables2 %}
{% block content %}
{% if ad_account %}
{% render_table context %}
{% endif %}
{% endblock %}
However this gives me the error: Expected table or queryset, not 'str'.
ANy help will be greately appreciated.
Right now I generate the table using this piece of code:
<table class="table table-bordered table-striped" id="campaigns">
<thead>
<tr>
<th> #</th>
<th> Campaign Name</th>
<th> Campaign Objective</th>
<th> Campaign Effective Status</th>
</tr>
</thead>
<tbody>
{% for campaign in campaigns %}
<tr>
<td> {{ forloop.counter }} </td>
<td>
<a href="/ad_accounts/{{ ad_account.id }}/campaigns/{{ campaign.id }}/ad_sets">
{{ campaign.name }} </a>
</td>
<td> {{ campaign.objective }}</td>
<td> {{ campaign.effective_status }} </td>
</tr>
{% endfor %}
</tbody>
</table>
You should pass a Table instance or queryset to the render_table tag.
{% render_table campaigns %}

django table information displayed twice

django table information displayed twice
Why is the Due date and time remaining appear twice? I am trying figure out what is that coming from. I am still learning django, slowly. Sometimes, I'm just having trouble.
Picture:
http://gyazo.com/cae11df54df3f558865a772529f97139.png
.html code
{% if toolsBorrowed %}
<table id="dataTable" width="100%" cellspacing="0" cellpadding="5" class="table table-hover">
<thead>
<tr>
<th>Tool Name</th>
<th>Owner</th>
<th>Due Date</th>
<th>Time Remaining</th>
</tr>
</thead>
<tbody id="myTable">
{% for tool in toolsBorrowed %}
{% query Request borrowerId=user.id as req %}
{% query userAcc pk=tool.owner as owner %}
<tr style="cursor: pointer;" onclick="document.location = '/view_tool/{{ tool.id }}/';">
<td>{{ tool.name }}</td>
<td>{% for o in owner %}{{ o.username }}{% endfor %}</td>
{% for r in req %}
<td>{{ r.dueDate }}</td>
<td>{{ r.dueDate | timeuntil }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<strong>You are not borrowing any tools.</strong>
{% endif %}
views.py
def borrowed(request):
context = {'toolsBorrowed': Tool.objects.filter(borrower = request.user.id),
'toolsLoan':Tool.objects.filter(owner = request.user.id).exclude(borrower = None),
'userAcc' : userAcc.objects,
'Request' : Request.objects,
}
return render(request, 'borrowed.html', context)
Any help would be great.

Counting objects and showing the results in Django

I have a question regarding counting objects, filtering the results and finally putting them into my template.
in Models.py:
class Fms(models.Model):
department = models.CharField(max_length=255, verbose_name='Department')
date = models.DateField()
in Views.py:
def raport(request):
raport = Fms.objects.filter(date__year='2013').extra(select={'month': "EXTRACT(month FROM date)"}).values('month', 'department').annotate(Count('department'))
return render_to_response ('Fms/raport.html',
{'raport': raport},
context_instance=RequestContext(request))
Question is, how to show a result in a table like:
Or at least make it show each month and how many times department was mentioned in that month.
you need something like:
{% for each_model in raport %}
{{each_model.department}}
{{each_model.date}}
{% endfor %}
If you do not pass a keyword to annotate, it uses the name of the field with __count appended to it. https://docs.djangoproject.com/en/dev/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset To access that in your template you would simply do:
<table>
<thead>
<tr>
<th>Month</th>
<th>Count</th>
</tr>
</thead>
<tbody>
{% for item in raport %}
<tr>
<td>{{ item.month }}</td>
<td>{{ item.department__count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
To display it horizontally...
<table>
<thead>
<tr>
{% for item in raport %}
<th>{{ item.month }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
{% for item in raport %}
<td>{{ item.department__count }}</td>
{% endfor %}
</tr>
</tbody>
</table>