DataTables server-side processing using Python (Flask/Postgresql) - python

Firstly, here is what I'm using : Python 3, Flask, PostgreSQL, a bootstrap theme.
What I want to do ?
I have a table with near 34000 values. The problem, the page is loading very slowly cause of the number of values. How can I improve performance using Server-Side processing (or other) with Python and Flask ?
Code :
Here is a part of my main.py :
#login_required
def home():
connect() # Connect to the PG database
connect.cur.execute("""SELECT * FROM test""")
test_execute = connect.cur.fetchall()
count_equipement()
return render_template('index.html',
value=test_execute,
value2=count_equipement.nb_equipement,
value3=check_ok.nb_ok,
value4=check_ko.nb_ko)
test_execute fetch all the values of my table. In my index.html here is how I show the data :
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>First</th>
<th>Second</th>
<th>Third</th>
<th>Fourth</th>
<th>Fifth</th>
</tr>
</thead>
<tfoot>
<tr>
<th>First</th>
<th>Second</th>
<th>Third</th>
<th>Fourth</th>
<th>Fifth</th>
</tr>
</tfoot>
<tbody>
{% for row in value %}
<tr>
<td>{{row[0]}}</td>
<td>{{row[1]}}</td>
<td>{{row[2]}}</td>
<td>{{row[3]}}</td>
<td>{{row[4]}}</td>
</tr>
{% endfor %}
</tbody>
</table>
In my bootstrap theme, there is a .js to paginate correctly the table. Here is the result with 8 values :
How can I do to do a server-side processing ? I've already check this link but I don't think I can apply this in my case...

Here is the answer of my question. (comments are in french)
#app.route('/stack', )
#app.route('/stack/<int:page>', defaults={'page': 1})
#login_required
def stack(page):
"""
retourne la page 1 par défaut, puis change selon le numéro /4 par ex
"""
connect()
connect.cur.execute("""SELECT COUNT(*) FROM mydatabase""")
count = connect.cur.fetchall()
count = count[0][0]
check.count()
PER_PAGE = 10
offset = ((int(page)-1) * PER_PAGE)
connect.cur.execute("""SELECT *
FROM mydatabase
ORDER BY table1 OFFSET %s LIMIT %s""" % (offset, PER_PAGE))
solutions = connect.cur.fetchall()
# Display a 409 not found page for an out of bounds request
if not solutions and page != 1:
return(render_template('404.html', errmsg="Requested page out of bounds"), 404)
pagination = Pagination(page, PER_PAGE, count)
return(render_template('index.html',
r=request,
value=solutions,
pagination=pagination))
def url_for_other_page(page):
"""
récupère l'url
"""
args = request.view_args.copy()
args['page'] = page
return url_for(request.endpoint, **args)
app.jinja_env.globals['url_for_other_page'] = url_for_other_page

Related

Flask FieldList can't change data

I am trying to generate a dynamic list of student from database, using FieldList and FormField. The fields are being generated using the data from database, but if I try to change something from the front-end, the back-end receives only the starting data (e.g., for checkbox it only gets False)
form:
class Beneficiary_Migration_Entry_Form(FlaskForm):
name = StringField('')
id = StringField('')
school = SelectField('', validate_choice=False)
student_class = SelectField('', validate_choice=False)
migrate = BooleanField('')
class Beneficiary_Migration_Form(FlaskForm):
entry_form_list = FieldList(FormField(Beneficiary_Migration_Entry_Form))
submit = SubmitField('Submit')
route
#app.route('/migration/student/<school_year_id>', methods=['GET', 'POST'])
#login_required
def student_migration_page(school_year_id):
school_year_id = int(school_year_id)
school_year = School_Year.query.filter(School_Year.id==school_year_id).first()
entry_form_list = []
school_list = Database_Manager.get_school_list(current_user)
school_choices = get_school_list()
entries = Student.query.filter(Student.user_id==current_user.id).all()
for entry in entries:
form = Beneficiary_Migration_Entry_Form(
name=entry.name,
id=entry.id,
)
id_str = str(entry.id)
form.name.name = 'name-' + id_str
form.school.name = 'school-' + id_str
form.migrate.name = 'migrate-' + id_str
form.student_class.name = 'student_class-' + id_str
form.id.name = 'id-' + id_str
form.school.choices = school_choices
form.student_class.choices = [('','')]
entry_form_list.append(form)
migration_form = Beneficiary_Migration_Form()
migration_form.entry_form_list = entry_form_list
school_map = Database_Manager.get_schools_map(current_user)
if migration_form.submit.data:
for form in migration_form.entry_form_list:
print(form.migrate.data)
return redirect(url_for('migration_page', school_year_id=school_year_id))
return render_template('migration-elev.html', school_map=school_map,school_year=school_year, migration_form=migration_form)
Front-end:
<form action="" method="post">
{{ migration_form.hidden_tag() }}
<table class="table table-striped table-dark" style="text-align: center;">
<thead class="thead-dark">
<tr>
<th scope="col">ID</th>
<th scope="col">Nume</th>
<th scope="col">Scoala</th>
<th scope="col">Clasa/ Grupa</th>
<th scope="col">Transfer</th>
</tr>
</thead>
<tbody>
{% for form in migration_form.entry_form_list %}
{{ form.hidden_tag() }}
<tr>
<td>{{form.id.value}}</td>
<td>{{form.name}}</td>
<td>{{form.school}}</td>
<td>{{form.student_class}}</td>
<td>{{form.migrate}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<p>{{ migration_form.submit(class_="btn btn-primary") }}</p>
</form>
At first it only got the data from the first entry from the FieldList, but I've found that I need to put unique names to work.
I've tried to use validate_on_submit but I get AttributeError: 'Beneficiary_Migration_Form' object has no attribute 'copy'.
I've also tried to use dictionaries and named tuples to load data, but I get the same result.
I've modified name to entry_name, since name is a reserved word.
To load data I've used append_data, where I've made a dictionary with data from db.

Update SQL query for HTML table Python

I have the following code in my Python project:
<table class="table table-striped">
<tr>
<th>Card Number</th>
<th>Card Name</th>
<th>Card Rarity</th>
<th>Card Quantity</th>
</tr>
{% for card in card_data %}
<tr>
<td>{{card.card_prefix}}</td>
<td>{{card.card_name}}</td>
<td>{{card.card_rarity}}</td>
<td>{{card.card_quantity}}</td>
</tr>
{% endfor %}
</table>
Is there a way to update the quantity to -1 or +1 on a button that only updates one row of the SQL database?
The current code in my main page is:
#app.route('/lob')
def lob():
session.clear()
cur = mysql.connection.cursor()
current_set = 'LOB'
session['set_selected'] = True
session['current_set'] = current_set
result = cur.execute("SELECT * FROM card_list WHERE card_set =%s", [current_set])
card_data = cur.fetchall()
if result > 0:
return render_template('/Booster Packs/lob.html', card_data=card_data)
else:
flash('Set Not Found!', 'danger')
return render_template('/Booster Packs/lob.html')
I can update the question with more information if needed, I'm just not sure how to go about how to select the value to update given the table.
Sorry for the bad English, it is not my first language.

Flask BuildError - Could not build URL for endpoint

I've got what should be a very simple python code to select some data from my database
#app.route('/studentsearch', methods = ['POST', 'GET'])
def searchstudent():
""" Displays the student search page for the site """
cursor = mydb.cursor()
cursor.execute ("SELECT * FROM student")
all_students = cursor.fetchall()
cursor.close()
return render_template('studentsearch.html', all_students = all_students)
But when I go to render the HTML page i get werkzeug.routing.BuildError: Could not build url for endpoint 'studentsearch'. Did you mean 'newstudent' instead?
My table is also pretty straight forward as well...
<table>
<thread>
<tr>
<th>Student ID:</th>
<th>First Name:</th>
<th>Last Name:</th>
<th>Click to View Student Details</th>
</tr>
</thread>
<tbody>
{% for each_result in all_students %}
<tr>
<td>{{ each_result[0] }}</td>
<td>{{ each_result[1] }}</td>
<td>{{ each_result[2] }}</td>
<td>CLICK HERE!!!</td>
</tr>
{% endfor %}
</tbody>
</table>
What's going on? 'newstudent' isn't even mentioned within the python or HTML??
As requested here's the code that the 'newstudent' appears to be coming from:
def newstudent():
"""Displays the new student page for the site"""
return render_template('newstudent.html')
#app.route('/process_newstudent', methods = ['POST', 'GET'])
def process_newstudent():
""" Processes the data from the new student course """
if request.method == 'POST':
first_name = request.form['firstname']
last_name = request.form['lastname']
year_began = request.form['yearbegan']
try:
cursor = mydb.cursor()
cursor.execute ("INSERT INTO student (first_name, last_name, year_began) VALUES ('{}','{}','{}');".format((first_name.title()), (last_name.title()), year_began))
mydb.commit()
cursor.close()
except mysql.connector.Error as err:
cursor.close()
return failure('newstudent', f"Error message: {err}. Student not added")
else:
cursor = mydb.cursor()
cursor.execute ("SELECT * FROM student")
student_success = cursor.fetchall()
cursor.close()
return render_template('newstudent_success.html', student_success = student_success)
else:
request.method == 'GET'
return render_template('newstudent.html')
Are you trying to build a dynamic URL somewhere in your application code or HTML code using the url_for function?
If you are, then I think what might be happening is that you're passing the parameter 'studentsearch' to that function instead of 'searchstudent' (url_for builds endpoints using the view function name, not the endpoint name). E.g. within an HTML template the URL in question would be built like this:
Search

Data table python flask

I have a question regarding mysql db python table in Bootstrap.
My question is my data is not shown in the table. I can see it gets data because of when I add row in mysql db with data the table increases.
app.py code:
#app.route('/dashboard')
#is_logged_in
def dashboard():
#create cursor
cur = mysql.get_db().cursor()
#Get data
result = cur.execute("SELECT * FROM test")
data=cur.fetchall()
if result > 0:
return render_template('dashboard.html', data=data)
else:
msg = 'No DOC Found'
return render_template('dashboard.html', msg=msg)
#close connection
cur.close()
return render_template('dashboard.html' )
.html
<table class="table table-striped">
<tr>
<th>data1</th>
<th>data2</th>
</tr>
{% for test in data%}
<tr>
<td>{{test.rdno}}</td>
<td>{{test.ipno}}</td>
{% endfor %}
</tr>
</table>
instead of
<td>{{test.rdno}}</td>
<td>{{test.ipno}}</td>
do this
<td>{{test[0]}}</td>
<td>{{test[1]}}</td>

Changing display order of tags in a table (Google App Engine-Python)

I have a table in UserAdminPage where tags are listed by alpha order (code below).
I want to add a link that will change the order to by date. I know I will change the query.order(owner_tag") to query.order("-date") but do I need to create a new handler?
I don't understand what the link should be where the question marks are.
Thanks
class UserAdminPage(webapp.RequestHandler):
def get(self):
...
#-----------tags table-----------------#
query = Owner.all()
query.filter("owner =", user)
query.order("owner_tag")
w = query.fetch(500)
user_tag_list = []
for item in w:
user_tag_list.append(item.owner_tag)
unique_tags = sorted(f1.f2(user_tag_list))
#-----------holding table start--------#
self.response.out.write("""
<table border="0" cellpadding="0" cellspacing="20" >
<tr>
<td>""")
#-----------tags table start--------#
self.response.out.write("""<table border="1">
<tr>
<th colspan="3">tags<br />
#the link that will sort by most recent:
#order tags by most recent</th>
</tr>
""")
for tag in unique_tags:
self.response.out.write("""
<tr>
<td>%s</td>
</tr>
""" %
(tag, tag)
)
self.response.out.write("""</table>""")
#holding table first column end
self.response.out.write("""</td>""")
#holding table second column start
self.response.out.write("""<td style="vertical-align:top">""")
UPDATED CODE AS PER KEVIN P'S ANSWER:
class UserAdminPage(webapp.RequestHandler):
def get(self):
order_by = self.request.get("order")
...
#-----------tags table-----------------#
query = Owner.all()
query.filter("owner =", user)
if not order_by:
query.order("owner_tag")
elif order_by == "date":
query.order("-date")
w = query.fetch(500)
user_tag_list = []
for item in w:
user_tag_list.append(item.owner_tag)
unique_tags = f1.f2(user_tag_list)
#-----------holding table start--------#
self.response.out.write("""
<table border="0" cellpadding="0" cellspacing="20" >
<tr>
<td>""")
#-----------tags table start--------#
# I put the link here but when I click on it, no table is drawn
# because the `for` block below draws the tag table
# so I don't understand how I can draw the table with `order=date`
self.response.out.write("""<table border="1">
<tr>
<th colspan="3">tags<br />
<span id=small>most recent</span></th>
</tr>
""")
for tag in unique_tags:
self.response.out.write("""
<tr>
<td>%s</td>
</tr>
""" %
(tag, tag)
)
self.response.out.write("""</table>""")
...
There are a number of ways to optimize your approach to this, but to answer your specific question - rather than duplicate your handler you could add a GET parameter to the link and then check for that while constructing your query:
class UserAdminPage(webapp.RequestHandler):
def get(self):
order_by = self.request.get('order')
query = Owner.all()
query.filter("owner =", user)
if not order_by:
query.order("owner_tag")
elif order_by == 'date':
query.order("-date")
...
order tags by most recent

Categories

Resources