I want to add an if function in an html template of my django project.
If the variables datas is null, it will show the text "The results is null", if the variables datas is not empty, it will show the table for the data in datas.
Here's what I write, but it raises the error
Invalid block tag on line 13: 'if(isEmpty($('#datas')))', expected 'endblock'.
Did you forget to register or load this tag?
How could I deal with it?
{% if(isEmpty($('#datas'))) %}
<h3>The results is null.</h3>
{% else %}
<table style="table-layout:fixed;">
<tr>...</tr>
<tr>
{% for i in datas %}
<td>{{ i.1 }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
I think you can use empty tag. Use it like this:
<table style="table-layout:fixed;">
<tr>...</tr>
<tr>
{% for i in datas %}
<td>{{ i.1 }}</td>
</tr>
{% empty %}
<h3>The results is null.</h3>
{% endfor %}
But, if you want to check if datas is empty beforehand, then I think its best to do it in views. You can try like this:
def some_view(request):
context = {}
datas = Data.objects.all()
if datas.exists():
context['data_exists'] = True
context['datas'] = datas
return render(request, 'template.html', context)
and use it template:
{% if not data_exists %}
<h3>The results is null.</h3>
{% else %}
....
You can directly use if condition
if you are sending datas from a view
view
def index(request):
datas = None
context = {"datas":datas}
return render(request, "index.html", context)
template
{% if datas %}
<!-- your table -->
{% else %}
<h3>The results is null</h3>
{% endif %}
Related
This is my first time using htmx and I'm trying to use the infinite scroll but it's not working. This is my code below
#app.route('/home', methods = ['GET'])
def home():
# pagination
page = request.args.get('page', 1, type=int)
all_data = Data.query.order_by(desc(Data.timestamp)).paginate(page = page, per_page = 20)
if "hx_request" in request.headers:
return render_template("table.html",datas = all_data)
return render_template("home.html", datas = all_data)
This is the html code i am trying to add the infinite scroll to
{% for data in datas.items %}
{% if loop.last and data.has_next %}
<tr hx-get="{{url_for('home', page = data.next_num)}}" hx-trigger="revealed" hx-swap="afterend">
{% else %}
<tr>
{% endif %}
<td scope="row">{{data.uuid}}</td>
<td scope="row">{{data.timestamp}}</td>
<td scope="row">{{data.decibel}}</td>
</tr>
{% endfor %}
And this is my home.html that contains the table
{% extends 'layout.html' %}
{% block head %}
<title>home</title>
{% endblock %}
{% block body %}
<center>
<table class="table table-primary table-striped" >
<tr>
<th scope="col">UUID</th>
<th scope="col">Timestamp</th>
<th scope="col">Decibel</th>
</tr>
<tbody>
{% include 'table.html' %}
</tbody>
</table>
</center>
{% endblock %}
I updated some things here and there but it's still not working
The following example shows you a not very nice way of using htmx infinite scroll. It's pretty similar to your approach.
from flask import (
Flask,
render_template,
request
)
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
class Record(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True, nullable=False)
with app.app_context():
db.drop_all()
db.create_all()
items = [Record(name=f'Record-{i}') for i in range(100)]
db.session.add_all(items)
db.session.commit()
#app.route('/')
def index():
page = request.args.get('page', 1, type=int)
records = Record.query.paginate(page=page, per_page=20)
return render_template('index.html', **locals())
A macro is defined which uses the paginate object to add the htmx pattern for each last row of the loaded chunk as long as there is another page.
The macro iterates over the elements of the loaded page, returning a table row for each entry. The attributes necessary for the infinite scroll pattern are added to the last row, provided there is another page.
In order to make the macro usable for other data records as well, the current object is sent back to the call within the iteration using caller(). This makes it usable as an argument in the nested block of the call.
See also the call section in the documentation for a more detailed explanation.
{% macro htmx_infinite_table_rows(paginate, endpoint) -%}
{% for item in paginate.items -%}
{% if loop.last and paginate.has_next -%}
<tr
hx-get="{{ url_for(endpoint, page=paginate.next_num) }}"
hx-trigger="revealed"
hx-swap="afterend"
>
{% else -%}
<tr>
{% endif -%}
{{ caller(item) }}
</tr>
{% endfor -%}
{% endmacro -%}
{% if 'hx_request' in request.headers -%}
{% call(record) htmx_infinite_table_rows(records, 'index') -%}
<td>{{ record.name }}</td>
{% endcall -%}
{% else -%}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.htmx-indicator {
display:none;
}
.htmx-indicator.htmx-request {
display:inline;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
{% call(record) htmx_infinite_table_rows(records, 'index') -%}
<td>{{ record.name }}</td>
{% endcall -%}
</tbody>
</table>
<center><img class="htmx-indicator" width="60" src="https://htmx.org/img/bars.svg"></center>
<script
src="https://unpkg.com/htmx.org#1.7.0"
integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo"
crossorigin="anonymous"
defer></script>
</body>
</html>
{% endif -%}
Update:
You made a mistake when getting the attributes has_next and next_num. The code should be as follows.
{% for data in datas.items %}
{% if loop.last and datas.has_next %}
<tr hx-get="{{url_for('home', page=datas.next_num)}}" hx-trigger="revealed" hx-swap="afterend">
{% else %}
<tr>
{% endif %}
<td scope="row">{{data.uuid}}</td>
<td scope="row">{{data.timestamp}}</td>
<td scope="row">{{data.decibel}}</td>
</tr>
{% endfor %}
So I am doing a django project. I have sent a dictionary(which holds a foreign key) to my html template. It has 'name'(which is a foreignkey),'bills','flat' keys. So when I am trying to print the name of a user it is actually printing the id of the user. But I want the name. I have used users = User.objects.all().values('name','bills','flat') and then passed the users in the template. The I tried to print like this:
{% for info in users %} {{info}} {% endfor %}
But instead of giving the name it is giving me the id number of the user.
My models.py file:
`
class Owner(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
class Payment(models.Model):
name=models.ForeignKey(Owner,on_delete=models.CASCADE,null=True)
flat = models.CharField(max_length=1,null=True,blank=True)
floor = models.IntegerField(default=0)`
My views.py file:
`
info = Payment.objects.all()
dict = {'1':[info.values('name','flat','floor','water_bill')]}
`
My Template file:
`
{% for j in dict.0 %}
<tr>
{% for i in j.values %}
<td>{{i}}</td>
{% endfor %}
</tr>
{% endfor %}
`
The return statement should look something like this,
return render_template(file.html, dict = dict)
Then you can use the dict variable in jinja as follows,
{% for j,k in dict %}
<tr>
{% for i in j.values %}
<td>{{i}}</td>
{% endfor %}
</tr>
{% endfor %}
I want to use the template to create all the tables of my project, but after writing is appearing errors like this:
jinja2.exceptions.TemplateSyntaxError: expected token ':', got '}'
{{ table(headers={{headers}},items={{item}},url='None') }}
I've looked at the jinja2 website but couldn't find the answer to the syntax error.
# python
#app.route('/products')
def products():
context = {}
qproducts = list(s.query(Product))
context['products'] = qproducts
return render_template('products.html', **context)
# table.html
{% macro table(headers,items,url,var) -%}
<table class='table table-sm table-dark'>
<thead>
<tr>
{{headers}}
</tr>
</thead>
<tbody>
{% for item in items %}
<tr onclick="window.location='{{url}}'">
{{items}}
</tr>
{% endfor %}
</tbody>
</table>
{%- endmacro %}
# products.html
{% from 'table.html' import table %}
{% block headers %}
<th>ID</th>
<th>Price</th>
{%endblock headers%}
{%block item%}
{%for item in products%}
<td>{{item.id}}<td><br>
<td>{{item.price}}<td><br>
{%endfor%}
{%endblock item%}
{{ table(headers={{headers}},items={{item}},url='None') }}
Even when you fix the references to variables (i. e. remove surrounding {{/}}) it won't work the way you expect. block tag can only be used with extends tag, but you use import for macros importing. If you want to write universal macro for table rendering it's better to use combination of macro/call tags:
{% macro table(headers,items,url,var) -%}
<table class='table table-sm table-dark'>
<thead>
<tr>
{{ caller(mode='header') }}
</tr>
</thead>
<tbody>
{% for item in items %}
<tr onclick="window.location='{{url}}'">
{{ caller(mode='row', item) }}
</tr>
{% endfor %}
</tbody>
</table>
{%- endmacro %}
caller here is a reference to a special function which invokes externally-provided callback. Then you can call this macro this way:
{% call(mode, items) table(headers=headers, items=item, url='None') %}
{% if mode='header' %}
<th>ID</th>
<th>Price</th>
{% else %}
{%for item in products%}
<td>{{item.id}}<td><br>
<td>{{item.price}}<td><br>
{% endfor %}
{% endif %}
{% endcall %}
Every mention of caller in macro table invokes body of the caller tag with the specified parameters. So, you can customize the behavior of the macro.
I'm designing a Flask application that works with a MySQL database.
I have this Flask code below:
#app.route("/test")
def test():
cursor.execute("SELECT * from testtable;")
data = cursor.fetchall()
return render_template('test.html', data = data)
I wish to make an HTML table from this data, and I want the first column of this table to be hyper-linked. My current test.html is shown below:
<table border="1" cellpadding="5" cellspacing="5">
{% for row in data %}
<tr>
{% for d in row %}
<td>{{ d }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
This HTML makes a hyper-link out of every cell in every column of the table. Is there a way to make only the cells in the first column be hyper-linked, and make all other cells just show {{ d }}?
The default template engine in Flask is jinja2.
In jinja2 you can check the loop index, which means that you could do something like the following.
{% for d in row %}
{% if loop.index == 1 %} # You can also use loop.index0 for 0-based indexing
<td>{{ d }}</td>
{% else %}
<td>{{ d }}</td>
{% endif %}
{% endfor %}
You can also skip the first element in the row list by using the following syntax:
{% for d in row[1:] %}
In your table, put for for loop outside the tr element.
<table border="1" cellpadding="5" cellspacing="5">
{% for row in data %}
<tr>
<td>{{ row.d }}</td>
{% endfor %}
</tr>
</table>
I am trying to call a python view method res() on django template but its not getting call.
This is my View
class make_incrementor(object):
def __init__(self, start):
self.count=start
def __call__(self, jump=1):
self.count += jump
return self.count
#property
def res(self):
self.count =0
return self.count
def EditSchemeDefinition(request, scheme_id):
iterator_subtopic = make_incrementor(0)
scheme_recs = scheme.objects.get(id=scheme_id)
view_val = {
'iterator_subtopic': iterator_subtopic,
"scheme_recs": scheme_recs,
}
return render(request, "edit.html", view_val)
I am Trying to Increment the count and later resetting it to 0 after a level But its reset method is not getting call from the Django template.
This is my edit.html page
<td id="subTopic" class="subTopic">
{% for strand in scheme_recs.stand_ids.all %}
{{ iterator_subtopic.res }}
{% for sub_strand in strand.sub_strand_ids.all %}
{% for topic in sub_strand.topic_ids.all %}
{% for subtopic in topic.sub_topic_ids.all %}
<input id="subTopic{{ iterator_subtopic }}" class="len"
value="{{ subtopic.name }}">
<br>
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
</td>
my {{ iterator_subtopic.res }} is not getting the call and the value of iterator_subtopic is not get set to 0 again. The Function and its call is working fine on Terminal but not rendering in django template.
Please correct me where i am doing wrong.
Thanks in advance.
Since your make_incrementor class has a __call__ method, I believe that {{ iterator_subtopic.res }} will first call iterator_subtopic(), which will return the count integer. It will then try to access the res attribute of the count integer (which doesn't exist), so it will output the empty string ''.
I simply modify my make_incrementor class methods like:-
class make_incrementor(object):
count = 0
def __init__(self, start):
self.count = start
def inc(self, jump=1):
self.count += jump
return self.count
def res(self):
self.count = 0
return self.count
def EditSchemeDefinition(request, scheme_id):
iterator_subtopic = make_incrementor(0)
scheme_recs = scheme.objects.get(id=scheme_id)
view_val = {
'iterator_subtopic': iterator_subtopic,
"scheme_recs": scheme_recs,
}
return render(request, "edit.html", view_val)
Later in my django template I called its method like:-
<td id="subTopic" class="subTopic">
<p hidden value="{{ iterator_subtopic.res }}"></p>
{% for strand in scheme_recs.stand_ids.all %}
{{ iterator_subtopic.res }}
{% for sub_strand in strand.sub_strand_ids.all %}
{% for topic in sub_strand.topic_ids.all %}
{% for subtopic in topic.sub_topic_ids.all %}
<input id="subTopic{{ iterator_subtopic.inc }}" class="len"
value="{{ subtopic.name }}">
<br>
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
And its done. Now i am getting my expected output.