Pagination with PyMongo and Flask - python

I found here a nice template for a pagination. However, this example was done with SQLlite, but I rewrote in order to be able to use PyMongo.
This script creates users and save them to MongoDB with help of PyMongo:
import sys
from pymongo import MongoClient
def fill_data(users_no):
for i in range(users_no):
doc = {
'_id': str(i),
'uname': "name_" + str(i),
}
sDB.insert(doc)
if __name__ == '__main__':
db = MongoClient().test
sDB = db.users
fill_data(1000)
I modified the orginal app.py script in onrder to be able to use PyMongo. This is the modified script:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from __future__ import unicode_literals
from flask import Flask, render_template, g, current_app, request
from flask.ext.paginate import Pagination
from pymongo import MongoClient
app = Flask(__name__)
app.config.from_pyfile('app.cfg')
#app.route('/')
def index():
db_name = "test"
col_name = "users"
db = MongoClient()
sDB = db[db_name][col_name]
total = sDB.find().count()
print total
page, per_page, offset = get_page_items()
users = sDB.find().skip(offset).limit(per_page)
for u in users:
print u
pagination = get_pagination(page=page,
per_page=per_page,
total=total,
record_name=users,
)
return render_template('index.html', users=users,
page=page,
per_page=per_page,
pagination=pagination,
)
def get_css_framework():
return current_app.config.get('CSS_FRAMEWORK', 'bootstrap3')
def get_link_size():
return current_app.config.get('LINK_SIZE', 'sm')
def show_single_page_or_not():
return current_app.config.get('SHOW_SINGLE_PAGE', False)
def get_page_items():
page = int(request.args.get('page', 1))
per_page = request.args.get('per_page')
if not per_page:
per_page = current_app.config.get('PER_PAGE', 10)
else:
per_page = int(per_page)
offset = (page - 1) * per_page
return page, per_page, offset
def get_pagination(**kwargs):
kwargs.setdefault('record_name', 'records')
return Pagination(css_framework=get_css_framework(),
link_size=get_link_size(),
show_single_page=show_single_page_or_not(),
**kwargs
)
if __name__ == '__main__':
app.run(debug=True)
Is there a way to avoid to use count() by clicking to the next or previous page in the pagination menu?
What did I forget to change so the actual user get be shown in the browser, because currently I only get the pagination menu without users?

User this link, It w'll help to paginate datas using flask-paginate
https://harishvc.com/2015/04/15/pagination-flask-mongodb/
if you are not using Flask use:
https://scalegrid.io/blog/fast-paging-with-mongodb/
Hope it will help !

Related

Passing Array into SQL query in Python

I am following the CS50 of Harvard and I don't want to use CS50 library that they use for lecture purposes, but I could not figure out how to make this code work. A little help would be greatly appreciated
import sqlite3
from flask import Flask, redirect, render_template, request, session
from flask_session import Session
# Configure app
app = Flask(__name__)
# Connect to database
db = sqlite3.connect("store.db",check_same_thread=False)
c = db.cursor()
# Configure sessions
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
#app.route("/")
def index():
books = db.execute("SELECT * FROM books")
list =[dict(id=book[0], title=book[1]) for book in books.fetchall() ]
return render_template("books.html", books=list)
#app.route("/cart", methods=["GET", "POST"])
def cart():
# Ensure cart exists
if "cart" not in session:
session["cart"] = []
# POST
if request.method == "POST":
id = request.form.get("id")
if id:
session["cart"].append(id)
return redirect("/cart")
# GET
books = db.execute("SELECT * FROM books WHERE id IN (?)", [session("cart")])
list =[dict(id=book[0], title=book[1]) for book in books.fetchall()]
return render_template("cart.html", books=list)
The error is at the books=db.execute... line.
Error is :
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 9 supplied
I pressed the cart button 9 times, it is incrementing. Tried other solutions, could not still figure out.
books = db.execute("SELECT * FROM books WHERE id IN (?)", [session("cart")])
should be
query = f"SELECT * FROM books WHERE id IN ({','.join(['?'] * len(session['cart']))})"
books = db.execute(query,session['cart'])))

Flask pagination help in Python

I'm trying to create a button in my HTML that will go to the next/previous page when the button is clicked. I've tried pagination and peewee but didn't seem to get it to work.
Here is my app:
from flask import Flask,render_template, request, json
from flask_mysqldb import MySQL
app = Flask(__name__)
app.config['MYSQL_HOST'] = 'example'
app.config['MYSQL_USER'] = 'example'
app.config['MYSQL_PASSWORD'] = 'example'
app.config['MYSQL_DB'] = 'fund_raiser'
mysql = MySQL(app)
#app.route('/funds/pages/', defaults={'page':0})
#app.route('/funds/pages/<int:page>')
def fund_pages(page):
perpage = 5
first_page = page*perpage
cur = mysql.connection.cursor()
cur.execute("select * from fund_table limit "+str(first_page)+", "+str(perpage)+";", mysql.connection.commit())
data = cur.fetchall()
return render_template('funds.html', data=data)
Where do I add the href tag in my html page? What is the correct variable to use?
This is quite easy with the url_for() function.
You can call the name of the function for the route, and pass it a variable.
href="{{ url_for('fund_pages', page=page_num) }}"
Where page_num is the page number.
To get the page number dynamically, you can simple add or subtract 1 from the current page number. For example, you could store page_prev = current_page - 1 and page_next = current_page + 1.
You can these pass those variables to the url_for function as the page parameter.
Example:
# in fund_pages()
prev_page = page - 1
next_page = page + 1
return render_template('template.hmtl', next_page=next_page, prev_page=prev_page)
# in the template
Previous
Next

Flask: use [GET, POST] function for a single URL

I'm new to Flask and wondering if it is possible to use the same URL to display a form in html and query to display something
Ideally, I want to have the following result to happen.
If I'm going to create a query inside 138.10.2.1/sample by doing this:
http://138.10.2.1:8000/sample?psi=1&lavr=1&dsc=1&ifsc=1&ics=1&eng=3&ol1=1&ol2=1&reso=1&educ=1&listen=1&time=1&probe=1&unders=1
It will display:
*something in json format*
in the webpage
Else, if I'll just go straight to this:
http://138.10.2.1:8000/sample
It will direct me to a .html page with a form to fill or allow a user to attach a file to use and upload to display a transformed file in json format also.
Here's my code
sample.py
from flask import Flask, flash, request, redirect, url_for, make_response, send_from_directory, render_template
import convert as ps
app = Flask(__name__)
#app.route("/sample", methods=["GET", "POST"])
def query_strings():
#This is not working: if request.method == "POST":
args1 = request.args["psi"]
args2 = request.args["lavr"]
args3 = request.args["dsc"]
args4 = request.args["ifsc"]
args5 = request.args["ics"]
args6 = request.args["eng"]
args7 = request.args["ol1"]
args8 = request.args["ol2"]
args9 = request.args["reso"]
args10 = request.args["educ"]
args11 = request.args["listen"]
args12 = request.args["time"]
args13 = request.args["probe"]
args14 = request.args["unders"]
args_list = [args1, args2, args3, args4, args5, args6, args7, args8,args9, args10, args11, args12, args13, args14]
result = ps.execute(args_list)
response = app.response_class(
response=result,
status=200,
mimetype='application/json'
)
return response
#This is my html form: return render_template("form.html")
if __name__ == '__main__':
app.run(debug = True)
Right now, what I can have is to run the query but I am getting prompted to enter the paramaters I declared if I just entered:
http://138.10.2.1:8000/sample
You can check the number of arguments and return the HTML form if the length is 0 like this:
# if there are no arguments provided, show HTML form
if len(request.args) == 0:
return render_template("form.html")
Also, there's no need to store each argument as a separate variable and then combine them into a list. request.args is already a dictionary so you can simply get a list of the argument names and values with:
list(request.args.keys()) # list of argument names eg. ['psi', 'lavr', 'dsc', 'ifsc'...]
list(request.args.values()) # list of argument values eg. [1, 1, 1, 1...]
You can check if the argument names match a desired set:
if set(argument_names) == {"psi","lavr","dsc","ifsc","ics","eng","ol1","ol2","reso","educ","listen","time","probe","unders"}:
# return JSON
Overall, your code could look something like this:
from flask import Flask, request, render_template
import json
app = Flask(__name__)
#app.route("/sample", methods=["GET", "POST"])
def query_strings():
# if there are no arguments provided, show HTML form
if len(request.args) == 0:
return render_template("form.html")
argument_names = list(request.args.keys())
# if the argument list is valid
if set(argument_names) == {"psi","lavr","dsc","ifsc","ics","eng","ol1","ol2","reso","educ","listen","time","probe","unders"}:
# return JSON
response = app.response_class(
response=json.dumps(request.args),
status=200,
mimetype='application/json'
)
return response
return "Invalid arguments"
if __name__ == '__main__':
app.run(debug = True)
This will:
show form.html if you load /sample with no arguments
show the arguments as JSON if you load /sample with valid arguments (eg. /sample?psi=1&lavr=1&dsc=1&ifsc=1&ics=1&eng=3&ol1=1&ol2=1&reso=1&educ=1&listen=1&time=1&probe=1&unders=1)
show "Invalid arguments" in any other case
Ohh..I see..so how can I have a .html to display if I don't enter any parameters? This will allow me to attach a file inside the html form and create to POST and get the same json result
Based on your comment to the question and sample code you've posted I assume you might be looking for something like this:
#app.route("/sample", methods=["GET", "POST"])
def query_strings():
args1 = request.args.get("psi")
args2 = request.args.get("lavr")
args3 = request.args.get("dsc")
args4 = request.args.get("ifsc")
args5 = request.args.get("ics")
args6 = request.args.get("eng")
args7 = request.args.get("ol1")
args8 = request.args.get("ol2")
args9 = request.args.get("reso")
args10 = request.args.get("educ")
args11 = request.args.get("listen")
args12 = request.args.get("time")
args13 = request.args.get("probe")
args14 = request.args.get("unders")
args_list = [
args1, args2, args3, args4, args5, args6, args7, args8,
args9, args10, args11, args12, args13, args14
]
if not all(args_list):
return render_template('form.html')
else:
result = ps.execute(args_list)
response = app.response_class(
response=result,
status=200,
mimetype='application/json'
)
return response
In this case, if you give no parameters in GET request it will render a template with html form.
Also rather than always check for request method I suggest you take a look at Flask's MethodView. Using that you can nicely split you logic onto request with arguments in the query string and form submitting with json:
http://flask.pocoo.org/docs/1.0/api/#flask.views.MethodView
Try this code, I hope it will help you. By default, it uses the GET method, so it is not working. When you click on the submit button then it calls the POST method.
from flask import Flask, flash, request, redirect, url_for, make_response, send_from_directory, render_template
import convert as ps
app = Flask(__name__)
#app.route("/sample", methods=["GET", "POST"])
def query_strings():
if request.method == "POST":
args1 = request.args["psi"]
args2 = request.args["lavr"]
args3 = request.args["dsc"]
args4 = request.args["ifsc"]
args5 = request.args["ics"]
args6 = request.args["eng"]
args7 = request.args["ol1"]
args8 = request.args["ol2"]
args9 = request.args["reso"]
args10 = request.args["educ"]
args11 = request.args["listen"]
args12 = request.args["time"]
args13 = request.args["probe"]
args14 = request.args["unders"]
args_list = [args1, args2, args3, args4, args5, args6, args7, args8,args9, args10, args11, args12, args13, args14]
result = ps.execute(args_list)
response = app.response_class(
response=result,
status=200,
mimetype='application/json'
)
# return response
return render_template("form.html", response = response)
return render_template("form.html")
#This is my html form: return render_template("form.html")
if __name__ == '__main__':
app.run(debug = True)

Can't implement braintree subscription on Flask

I have this app
import braintree
from flask import Flask, render_template, send_from_directory, request
try:
from ConfigParser import SafeConfigParser
except ImportError:
from configparser import SafeConfigParser
app = Flask(__name__)
parser = SafeConfigParser()
parser.read('secrets.ini')
MERCHANTID = parser.get('braintree', 'MERCHANTID')
PUBLICKEY = parser.get('braintree', 'PUBLICKEY')
PRIVATEKEY = parser.get('braintree', 'PRIVATEKEY')
braintree.Configuration.configure(braintree.Environment.Sandbox,
merchant_id=MERCHANTID,
public_key=PUBLICKEY,
private_key=PRIVATEKEY)
#app.route("/")
def index():
# Generate client token for the dropin ui
client_token = braintree.ClientToken.generate({})
return render_template('index.html', token=client_token)
#app.route("/proc", methods=['GET', 'POST'])
def proc():
# result = braintree.Transaction.sale({
# "amount": request.form["amount"],
# "payment_method_nonce": request.form["payment_method_nonce"]
# })
# print(result)
result = braintree.Customer.create({
"credit_card": {
"number": "4111111111111111",
"expiration_date": "12/16"
}
})
result = braintree.Subscription.create({
"payment_method_token": result.customer.credit_cards[0].token,
"plan_id": "upwork_sub"
})
return render_template('proc.html', result=result, request=request.form)
if __name__ == "__main__":
app.run(host='0.0.0.0')
The one time charge(the code that is commented) works fine.
The problem is when I want to charge with subscription I have to hard create the Client and then auto charge with subscription.
How I can make it without hard coding the clients info

Flask and Sqlite3 INSERT works only locally

im working with Flask and Sqlite3.and i've written a code which inserts 3 value into a sqlite3 database.
from flask import Flask, render_template, g, request, redirect, url_for, flash, session
from functools import wraps
from flask_bootstrap import Bootstrap
from wtforms import Form, StringField, PasswordField, DateTimeField
from wtforms.validators import InputRequired
import os
import sqlite3
from datetime import datetime
app = Flask(__name__)
Bootstrap(app)
app.secret_key = os.urandom(24)
app.config.from_object(__name__)
D_candata = '/var/www/FlaskApp/py/static/database/CANData.db'
D_acc = '/var/www/FlaskApp/py/static/database/acc.db'
D_appo ='/var/www/FlaskApp/py/static/database/appo.db'
class LoginForm(Form):
username = StringField(validators=[InputRequired(message='Username ist noch leer')])
password = PasswordField(validators=[InputRequired(message='Password ist noch leer')])
class DateForm(Form):
bdt = DateTimeField(validators=[InputRequired(message='Bitte eingeben')], format = '%d-%m-%Y %H:%M' )
edt = DateTimeField(validators=[InputRequired(message='Bitte eingeben')], format = '%d-%m-%Y %H:%M' )
def connect_db(db):
return sqlite3.connect(db)
def loggin_required(funct):
#wraps(funct)
def wrap(*args, **kwds):
if 'logged_in' in session:
return funct(*args, **kwds)
else:
flash('log in!!')
return redirect(url_for('login'))
return wrap
#app.route('/')
#loggin_required
def index():
g.db = connect_db(D_candata)
cur = g.db.execute('SELECT * FROM CANData LIMIT 1;')
data = [dict(Timestamp=row[0], BatteryVoltage=row[1], BatteryAmperage=row[2], BatteryLoad=row[3], Range=row[4], Speed=row[5], Mileage=row[6]) for row in cur.fetchall()]
g.db.close()
return render_template ("/html/index.html", data=data)
#app.route('/reservierung/', methods = ["GET","POST"])
#loggin_required
def reservie():
form = DateForm(request.form)
b_date = ""
e_date = ""
if request.method == "POST" and form.validate() :
b_date = form.bdt.data
e_date = form.edt.data
if b_date > e_date :
flash('Bitte den Zeitraum korrigieren ')
else:
account = 'admin'
try:
con = connect_db(D_appo)
cur = con.cursor()
flash('ok1')
cur.execute("INSERT INTO appo_info (account, b_date, e_date) VALUES (?, ?, ?)",(account, b_date, e_date)) #???
flash('ok')
con.commit()
con.close()
except:
flash('500')
con.rollback()
return render_template('/html/reservie.html', form=form)
if __name__ == "__main__":
app.run(debug=True)
i think the problem start with
def reservie():
...
cur.execute("INSERT INTO appo_info (account, b_date, e_date) VALUES (?, ?, ?)",(account, b_date, e_date))
because i've use flash and try to show where it goes wrong.
and it just show ('ok1')and ('500') when i use chrome at computer(server is raspberry).
but it did show ('ok') when i tested it at raspberry. and the datas shows in database.
At raspberry pi I can read and write. But at computer i can only read
Im sure is it not the problem from Authentication. The databases and others is already '777'
i cant use debug mode, because it is not local. so did anyone have an idea?
thx a lot

Categories

Resources