How to pass massive data from flask to template? - python

I have the data that get from database, the data is about more that 30,000 record, when i render the template with these data, the template is very slow, so what is the best way to pass the massive data and display on template.
This is my code.
route.py
#app.route('/index', methods=['GET', 'POST'])
def index():
asset_table = asset.query.all()
return render_template('index.html', asset_table=asset_table)
index.html
<table class="table table-hover table-sm table-striped" id="asset_table">
<thead class="thead-dark">
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
{% for asset in asset_table %}
<tr>
<td>{{ asset.asset_id }}</td>
<td>{{ asset.asset_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
$(document).ready(function () {
$('#asset_table').DataTable({
"scrollX": true,
});
$('.dataTables_length').addClass('bs-select');
});
</script>
models.py
from application import db
class asset(db.Model):
__tablename__ = 'asset'
asset_id = db.Column(db.String(30), primary_key=True)
asset_name = db.Column(db.String(30))

I would use a library called sqlalchemy-datatables which is a bit old now but does it work.
The code should look like this:
Flask Code
from datatables import ColumnDT, DataTables
#app.route('/index', methods=['GET'])
def index():
"""
Code which renders the index page
"""
return render_template('index.html')
#app.route('/data', methods=['GET'])
def data():
"""
Returns data for the index page.
GET:
params:
Please learn about the other parameters here:
https://datatables.net/manual/server-side#Sent-parameters
responses:
Please learn about the response parameters here:
https://datatables.net/manual/server-side#Returned-data
"""
columns = [
ColumnDT(
asset.asset_id,
mData="ID"
),
ColumnDT(
asset.asset_name,
mData="Name"
)
]
query = db.session.query().select_from(asset)
params = request.args.to_dict()
rowTable = DataTables(params, query, columns)
return jsonify(rowTable.output_result())
HTML/Jquery Code
<table class="table table-hover table-sm table-striped" id="asset_table">
<thead class="thead-dark">
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
$(document).ready(function () {
$('#asset_table').DataTable({
processing: true,
serverSide: true,
ajax: "{{ url_for('data')}}",
dom: 'Bflrtip',
columns: [
{ "data": "ID" },
{ "data": "Name" },]
});
});
</script>
Cheers!

Related

Making numbers easier to read using filters

So I am trying to convert numbers on my website to look a bit nicer, such as 3217210 instead should be 3,217,210 I have tested a few threads but didn't get it to work.
My website takes these values from an API.
Heres my HTML:
<tbody>
{% for product in products %}
<tr>
<td>{{ product.id|replace("_", ' ')|lower()|title() }}</td>
{% for buy in product.buy_price %}
<td>{{ buy.pricePerUnit }}</td>
{% for sell in product.sell_price %}
<td>{{ sell.pricePerUnit }}</td>
<td>{{ product.buy_volume|numberFormat }}</td>
<td>{{ product.sell_volume}}</td>
{% set margin = buy.pricePerUnit - sell.pricePerUnit%} {% set marginPer
= margin/buy.pricePerUnit * 100%}
<td
aria-label="{{ marginPer|round(1, 'floor') }} % "
data-balloon-pos="right"
>
{{ margin|round(1, 'floor')}}
</td>
{% endfor %}{% endfor %}
</tr>
{% endfor %}
</tbody>
And here is my python:
#app.route('/bprices', methods=['GET'])
def bPrices():
f = requests.get(
'https://api.hypixel.net/skyblock/bazaar?key=[cant show]').json()
products = [
{
"id": product["product_id"],
"sell_price": product["sell_summary"][:1],
"buy_price": product["buy_summary"][:1],
"sell_volume": product["quick_status"]["sellVolume"],
"buy_volume": product["quick_status"]["buyVolume"],
}
for product in f["products"].values()
]
return render_template("bprices.html", products=products)
Thanks:)
You can use global template filter in flask code and then use it in template. You can read the official documentation on custom template filter.
app.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.template_filter()
def numberFormat(value):
return format(int(value), ',d')
#app.route("/", methods=["GET"])
def home():
products = [
{
"name": "mobile",
"quantity": 3217210
},
{
"name": "laptop",
"quantity": 343217210
},
{
"name": "mouse",
"quantity": 100
}
]
return render_template("index.html", products=products)
index.html:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Number format</title>
</head>
<body>
<h3>Products</h3>
<table border="1">
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td>{{ product.name }}</td>
<td>{{ product.quantity | numberFormat }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
Output:
You can modify the filter as per your requirements.

Loop through items into Django 1.8 template

I have this method:
def profile(request):
parsedData = []
if request.method == 'POST':
username = request.POST.get('user')
req = requests.get('https://api.github.com/users/' + username + '/repos')
jsonList = []
jsonList=req.json()
userData = {}
for data in jsonList:
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
return render(request, 'app/profile.html', {'data': parsedData})
This code looks into an url like this githubtraining
As You can see, the response contains lots of repositories, however, not every github user has more than 1 repo.
Anyways, on my html view I have this:
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped tablesorter">
<thead>
<tr>
<th class="header"> Url <i class="icon-sort"></i></th>
<th class="header"> Created at <i class="icon-sort"></i></th>
<th class="header"> Updated at <i class="icon-sort"></i></th>
<th class="header"> Forks count <i class="icon-sort"></i></th>
</tr>
</thead>
<tbody>
{% for key in data %}
<tr>
<td>{{ key.html_url }}</td>
<td>{{ key.created_at }}</td>
<td>{{ key.updated_at }}</td>
<td>{{ key.forks_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
What happens then? Well, right now, if, for instance, I query the githubtraining user to see it's repos, it shows only the last one, on that and every other user, so, what am I doing wrong here? The loop is there, what am I missing?
You append data only after forloop is finished inside your view. You need to append it after each iteration instead:
for data in jsonList:
userData = {}
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
With your current code:
userData = {}
for data in jsonList:
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
new userData overrides previous one inside for cycle. And when cycle finishing you have only one record in the list.

Edit form creates new data instead

I defined a route and template to edit data. Instead, it creates new data. How do I fix this?
#home_blueprint.route('/table/<int:data_id>/edit', methods=['GET', 'POST'])
def edit(data_id):
ed_form = EditTableForm(request.form)
data_to_edit = db.session.query(Diary).filter_by(id=data_id)
if ed_form.validate_on_submit():
if ed_form.title.data:
data_to_edit.title = ed_form.title.data
if ed_form.weight.data:
data_to_edit.weight = ed_form.weight.data
if ed_form.kkal.data:
data_to_edit.kkal = ed_form.kkal.data
if ed_form.carbs.data:
data_to_edit.carbs = ed_form.carbs.data
if ed_form.proteins.data:
data_to_edit.proteins = ed_form.proteins.data
if ed_form.fats.data:
data_to_edit.fats = ed_form.fats.data
db.session.add(data_to_edit)
db.session.commit()
flash('New data was successfully posted. Thanks.')
return redirect(url_for('home.table'))
else:
return render_template('edit.html', data_to_edit=data_to_edit, ed_form=ed_form, data_id=data_id)
return render_template("edit.html", diary=diary)
<table class="table table-bordered">
<thead>
<tr>
<th>Product</th>
<th>Weith</th>
<th>Kkal</th>
<th>Protein</th>
<th>Fat</th>
<th>Carbs</th>
</tr>
</thead>
<tbody>
{% for data in data_to_edit %}
<tr>
<form class="form-message" role="form" method="post" action="/table">
{{ ed_form.csrf_token }}
<td>{{ed_form.title(placeholder=data.title)}}</td>
<td>{{ed_form.weight(placeholder=data.weight)}}</td>
<td>{{ed_form.kkal(placeholder=data.kkal)}}</td>
<td>{{ed_form.carbs(placeholder=data.carbs)}}</td>
<td>{{ed_form.proteins(placeholder=data.proteins)}}</td>
<td>{{ed_form.fats(placeholder=data.fats)}}</td>
<td><button class="btn btn-sm btn-success" type="submit">Post</button></td>
</form>
</tr>
{% endfor %}
</tbody>
</table>
Link to projects Git repository. Each users input into table has own id, I query data by id and then trying to Edit data there with no luck so far :)
UPDATE
I have changed code to:
data_to_edit = db.session.query(Diary).filter_by(id=data_id).first()
if ed_form.validate_on_submit():
if not data_to_edit:
data_to_edit = Diary(
ed_form.title.data,
ed_form.weight.data,
ed_form.kkal.data,
ed_form.carbs.data,
ed_form.proteins.data,
ed_form.fats.data,
current_user.id
)
db.session.add(data_to_edit)
db.session.commit()
But yet no luck, it doesn't change old data but ads new.
The issue is that you are adding the object again in session, thus inserting it into the database.
Sample code
data_to_edit = db.session.query(Diary).filter_by(Diary.id=data_id).first()
if not data_to_edit:
data_to_edit = Diary()
db.session.add(data_to_edit)
...
# edit properties
...
db.session.commit()
The idea is to add the new object only when it's actually new.

Blank screen error on google app engine

I am trying out this idea where there is a table of 'events' on a '/search' page and when a 'GO' button of an event is pressed, it will increment the 'RSVP' count of that event, and redirect back to '/search'. However, when I clicked on the 'GO' button in my application, it leads to a blank screen with url 'localhost:8080/rsvp'.
Finding it strange and wondering which part of my code is wrong. Here are some of the relevant parts of the code that I think is causing the error.
This is the code from the python file:
class RSVPItem(webapp2.RequestHandler):
# increment RSVP count when GO button is clicked
def post(self):
itemkey = ndb.Key('Items', self.request.get('itemid'))
item = itemkey.get()
item.rsvp = item.rsvp + 1
item.put()
self.redirect('/search')
# Handler for the Search page
class Search(webapp2.RequestHandler):
# Display search page
def get(self):
user = users.get_current_user()
if user: # signed in already
# Retrieve items
query = ndb.gql("SELECT * "
"FROM Items ")
template_values = {
'user_mail': users.get_current_user().email(),
'logout': users.create_logout_url(self.request.host_url),
'items': query,
}
template = jinja_environment.get_template('search.html')
self.response.out.write(template.render(template_values))
else:
self.redirect(self.request.host_url)
app = webapp2.WSGIApplication([('/', MainPage),
('/giftbook', MainPageUser),
('/wishlist', WishList),
('/deleteitem', DeleteItem),
('/search', Search),
('/rsvp', RSVPItem),
('/display', Display),
('/displaytag', Displaytag)],
debug=True)
This is from the html file for 'search.html'. Only showing the part I think is relevant.
<h4> Events List </h4>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th width="10%">Name</th>
<th>Description</th>
<th width = "10%">Link</th>
<th width = "10%">Date</th>
<th width = "10%">Type</th>
<th width = "10%">RSVP</th>
<th width = "10%">Rolling?</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.event_name }} </td>
<td>{{ item.description }}</td>
<td>{{ item.event_link}}</td>
<td>{{ item.date.strftime('%Y-%m-%d') }}</td>
<td>{{ item.event_type}}</td>
<td>{{ item.rsvp }}
<td>
<form action="/rsvp" method="post">
<input type="hidden" name="itemid" value="{{ item.item_id }}">
<input type="submit" value="GO!">
</form></td>
</tr>
{% endfor %}
</tbody>
</table>
<form action="/rsvp" method="post"> sends them to /rsvp. Do you have a url handler for /rsvp?
Make sure you cast the Key to an int:
itemkey = ndb.Key('Items', int(self.request.get('itemid')))
Instead of setting your own id item_id, just use the built-in Key:
<input type="hidden" name="itemid" value="{{ item.key.id() }}">
Check the logs to see if there are any errors.

Appengine - how to get an entity and display values

I'm having trouble with my project. I have 2 models
class UserPrefs(db.Model):
user = db.UserProperty()
name = db.StringProperty()
class Person(db.Model):
name = db.StringProperty()
phone = db.PhoneNumberProperty()
userPrefs = db.ReferenceProperty(UserPrefs)
class PersonHandler(webapp.RequestHandler):
def get(self):
users.get_current_user user = ()
if user:
greeting = ......
else:
greeting = ......
if self.request.GET.has_key ('id'):
id = int (self.request.get ['id'])
person = models.Person.get = (db.Key.from_path ('Person', id))
path = os.path.join (os.path.dirname (__file__), 'templates / doStuff.html')
self.response.out.write (template.render (path, locals (), debug = True))
def post (self):
if self.request.get ('Person'):
id = int (self.request.get ('Person'))
person = models.Person.get (db.Key.from_path ('Person', id))
else:
person= models.Person = ()
data = forms.PersonForm date = (data = self.request.POST)
if data.is_valid ():
if self.request.get ('photo'):
Person.foto db.Blob = (self.request.get ('photo'))
person.nome self.request.get = ('name')
person.apelido self.request.get = ('name')
person.unidade self.request.get = ('unit')
person.put ()
self.redirect ('/ doSomeStuff')
else:
self.redirect ('doOtherStuff')
To See the data in database i use this handler:
class SeePersonHandler (webapp.RequestHandler):
def get (self):
users.get_current_user user = ()
if user:
greeting = ......
else:
greeting = ......
person= db.Query(models.Pocente)
persons = person.fetch(limit = 1)
path = os.path.join(os.path.dirname(__file__), 'templates/SeeStuff.html')
self.response.out.write(template.render(path, locals(), debug = True))
Question:
I knows that the data is put corectly. I used the SDK Console with this url: http://localhost:8080/_ah/admin/datastore and the entity is created correctly. I donĀ“t know what i am missing to retrieve the dadta already put
My Template:
{% if user %}
{% if person%}
<table align="center">
<tbody>
<tr>
<td><input type="button" value="Criar Pessoa" onclick="redirect(3)" /></td>
</tr>
</tbody>
</table>
<table align="center">
<tbody>
<tr>
<td colspan="2"><center><strong><p>O meu Curriculum Vitae</p></strong></center></td>
</tr>
<tr>
<td>Nome: </td>
<td>{{ person.name}}</td>
</tr>
<tr>
<td>Apelido: </td>
<td>{{ person.phone}}</td>
</tr>
<tr>
<td></td>
<td>
<input type ="button" value="Editar" onclick="editarCv({{ person.key.id }})" />
</td>
</tr>
</tbody>
</table>
{% endif %}
{% endif %}
Your code is a bit disorganised.
Debugging is generally easier with better-organised code.
Anyway, enough of the trash-talking.
You're assigning the result of a datastore query to persons...
persons = person.fetch(limit = 1)
...but then in your template you use person:
<tr>
<td>Nome: </td>
<td>{{ person.name}}</td>
</tr>
<tr>
<td>Apelido: </td>
<td>{{ person.phone}}</td>
</tr>
It is difficult to tell if this is your only problem (I highly doubt it), but perhaps you can try fixing that and get back to us. Best of luck to you.
Aside: instead of .fetch(limit=1) you can simply use .get() as mentioned in the documentation:
get() implies a "limit" of 1. At most
1 result is fetched from the
datastore.

Categories