Why is my function not printing anything in the CLI? - python-3.x

At the moment I am just trying to get the function to print what it has found in
the database, however I am not getting anything in the CLI when submitting
eywords via a form which has this functions URL as an action.
import os
from flask import Flask, render_template, redirect, request, url_for
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
app = Flask(__name__)
app.config["MONGO_DBNAME"] = 'recipe_site'
app.config["MONGO_URI"] = os.getenv("MONGO_URI")
mongo = PyMongo(app)
#function for search bar.
#app.route('/search', methods=['GET', 'POST'])
def search():
mongo.db.recipes.create_index( { "name": "text" } )
if request.method == "POST":
q = request.form['search']
else:
q = ""
query = ( { "$text": { "$search": q } } )
results = mongo.db.recipes.find(query)
return render_template('searchresults.html', recipes = results)
The form that calls search function and captures key search word:
<form action="{{ url_for('search', text=text) }}" method="POST">
<div>
<div class="input-field">
<input id="search" name="search" type="text" class="validate">
<span class="helper-text" data-error="Try again" data-success="Done"></span>
</div>
</div>
<button type="submit">Submit </button>
</form>
Error code
Debugger PIN: 272-267-243
10.240.1.220 - - [25/May/2019 19:24:14] "POST /search/ HTTP/1.1" 404 -
As the code stands now all I expect is that it should print any collections in my database which have the keyword searched using the form.

You need to read the key words received from the post request using request.form['search']
like below:
#function for search bar.
#app.route('/search', methods=['GET', 'POST'])
def search():
# index for field name
mongo.db.recipes.create_index('name')
# index for field name and example
#mongo.db.recipes.create_index([("name", pymongo.DESCENDING),
#("example", pymongo.ASCENDING)])
if request.method == "POST":
q=request.form['search']
else:
q = ""
query = ( { "$text": { "$search": q } } )
results = mongo.db.recipes.find(query)
print (results)
return render_template('searchresults.html', recipes = results)
In the form, you need to replace
<form action="{{ url_for('search', text=text) }}" method="POST">
By
<form action="{{ url_for('search') }}" method="POST">
Edit:
I suggest to use GET method instead of POST for search feature because when the client refresh the browser, it ask him to confirm Form submission. So we need to replace:
if request.method == "POST":
q=request.form['search']
else:
q = ""
By
q = request.args.get('search', "")
And
<form action="{{ url_for('search') }}" method="POST">
by
<form action="{{ url_for('search') }}" method="GET">

Using the official documentation for PyMongo
Here is a tested code that might help.
from flask import Flask
from flask_pymongo import PyMongo
import pymongo
app = Flask(__name__)
app.config["MONGO_DBNAME"] = 'test'
app.config["MONGO_URI"] = "mongodb+srv://<username>:<password>#cluster0-vhd1j.gcp.mongodb.net/test?retryWrites=true"
mongo = PyMongo(app)
# mongo.db.collection.create_index([("name", pymongo.ASCENDING),("text", pymongo.ASCENDING)])
mongo.db.collection.insert_one({"name":"myname","text":"abcd"})
query = { "text": "abcd"}
results = mongo.db.collection.find(query)
for result in results:
print(result)
you can manipulate it as per your requirement. :)
I hope it helps.

Thank you for your attempts to support but I have now rectified the issue. The reason why nothing was printing in the cli was due the there being an issue with the create_index line. There was an existing index within that collection i was unaware of which was preventing this line from running.

Related

Flask app is not allowing me to use session or g to store file path

I am currently working on a school project using flask and I have ran into a bug that I can't seem to solve the problem is that I need to send a file path to the identify unit function in order for it to convert the pdf file into a dataframe but I can't seem to get it working Here is my code.
from flask import Flask, render_template, request,g,redirect,url_for,session
from wtforms import Form, FileField, validators
from wtforms import SelectMultipleField
import os
import random
import pandas as pd
import SMBH
app = Flask(__name__,template_folder='/home/kronos/GPFS-1/Templates')
# clear tmp directory
dir = '/home/kronos/GPFS-1/tmp'
for f in os.listdir(dir):
os.remove(os.path.join(dir, f))
# configure the app
app.config['SECRET_KEY'] = 'udOAg]!YzPC}=%WW}3"+K>E*[x7`XV&iGExmEDz>|4fbL$a51{J.VNQW7_9a4oO'
app.config['MAX_CONTENT_LENGTH'] = 64 * 1024 * 1024
# identify unit form
class FileForm(Form):
file = FileField('File')
class TaskForm(Form):
tasks = SelectMultipleField('Tasks')
#app.route('/upload', methods=['GET', 'POST'])
def identify_unit():
marks = SMBH.Markbook()
marks.extract_tables(session['full_path'])
df=marks.data()
form = TaskForm()
form.tasks.choices = [(task, task) for task in df["Task"]]
if request.method == 'POST':
selected_tasks = request.form.getlist('tasks')
grade_categories = [task for task in selected_tasks if request.form.get(task) == 'grade']
unit_categories = [task for task in selected_tasks if request.form.get(task) == 'unit']
for index, row in df.iterrows():
task = row["Task"]
if task in grade_categories:
current_unit = None
elif task in unit_categories:
current_unit = task
current_grade_group = None
df.at[index, "Unit"] = current_unit
df.at[index, "Grade Group"] = current_grade_group
df["Grade Group"] = df["Grade Group"].fillna(method='ffill')
return str(df)
return render_template('identify_unit.html', form=form)
def upload():
form = FileForm()
if request.method == 'POST':
file = request.files['file']
filename = str(random.randint(1000000000,9999999999))
file.save(os.path.join("/home/kronos/GPFS-1/tmp", filename+'.pdf'))
session['full_path'] = os.path.join("/home/kronos/GPFS-1/tmp", filename+'.pdf')
return redirect(url_for('identify_unit'))
return render_template('Upload.html', form=form)
app.run(debug=True)
This is the HTML
<form method="POST" action="{{url_for('identify_unit')}}">
{% for task in form.tasks %}
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="{{ task.name }}" id="grade_{{ task.name }}" value="grade">
<label class="form-check-label" for="grade_{{ task.name }}">Grade</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="{{ task.name }}" id="unit_{{ task.name }}" value="unit">
<label class="form-check-label" for="unit_{{ task.name }}">Unit</label>
</div>
{{ task }}
<br>
{% endfor %}
<input type="submit" value="Submit">
</form>
I have tried g and session but get errors along the lines of variable is not defined or one time DataFrame is not JSON serializable

Python3 Flask & Sqlite3 - Can't insert into database

I can't make my code work. I've been looking around for tutorials and guides but to no avail. If anyone see the mistake I'm doing, it would be very helpful.
Here is the folder structure:
/
application.py
database.db
/routes
__init__.py
signup.py
/templates
signup.html
Here is my signup.py:
import sqlite3
from flask import Blueprint, render_template, redirect, session, request, flash
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
# Set Blueprints
signup = Blueprint('signup', __name__,)
#signup.route("/signup", methods=["GET", "POST"])
def signupFunction():
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
try:
email = request.form.get("email")
username = request.form.get("username")
password = request.form.get("password")
confirmPassword = request.form.get("confirm-password")
with sqlite3.connect("./database") as connection:
print("Opened database successfully")
current = connection.cursor()
# Ensure email was submitted
if not email:
return flash("must provide email")
# Ensure username was submitted
if not username:
return flash("must provide username")
# Ensure password was submitted
if not password:
return flash("must provide password")
# Ensure confirm password is correct
if password != confirmPassword:
return flash("The passwords don't match")
# Query database for username if already exists
current.execute("SELECT * FROM users WHERE username = :username", username=username)
if current.fetchall() == username:
return flash("Username already taken")
# Insert user and hash of the password into the table
current.execute("INSERT INTO users(username, hash) VALUES (:username, :hash)", username=username, hash=generate_password_hash(password))
current.commit()
# Query database for username
current.execute("SELECT * FROM users WHERE username = :username", username=username)
rows = current.fetchall()
# Remember which user has logged in
session["user_id"] = rows[0]["id"]
# Commit to databse
connection.commit()
print("Database operation succesful")
except:
connection.rollback()
print("Error in sign up operation")
finally:
# Close database connection
connection.close()
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("signup.html")
here is my signup.html
{% extends "layout.html" %}
{% block title %}
Sign Up
{% endblock %}
{% block main %}
<p>Register or <a href='/signin'>login</a></p><br>
<form action="/signup" method="post">
<div>
<p>Username (6 characters min).</p>
<input id="username" autocomplete="off" autofocus class="form-control" name="username" placeholder="Username" type="text">
</div>
<br>
<div>
<p>Email.</p>
<input id="email" autocomplete="off" autofocus class="form-control" name="email" placeholder="Email" type="text">
</div>
<br>
<div>
<p>Password (7 to 15 characters, 1 numeric, 1 special).</p>
<input id="password" name="password" placeholder="Password" type="password">
</div>
<div>
<input id="confirm-pass" name="confirm-password" placeholder="Confirm Password" type="password">
</div>
<br>
<button id="submit" type="submit">Sign Up</button>
<br>
</form>
<script>
// Password must be between 7 to 15 characters which contain at least one numeric digit and a special character
document.querySelector("#submit").disabled = true;
document.querySelector("#confirm-pass").onkeyup = function() {
let password = document.querySelector("#password").value;
let username = document.querySelector("#username").value;
let email = document.querySelector("#email").value;
let confirmation = document.querySelector("#confirm-pass").value;
if (password.match(/^^(?=.*[0-9])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]{7,15}$/i)) {
document.querySelector("#submit").disabled = true;
if (email.match(/^(([^<>()\[\]\.,;:\s#\"]+(\.[^<>()\[\]\.,;:\s#\"]+)*)|(\".+\"))#(([^<>()[\]\.,;:\s#\"]+\.)+[^<>()[\]\.,;:\s#\"]{2,})$/i)) {
document.querySelector("#submit").disabled = true;
if (username.length > 5) {
document.querySelector("#submit").disabled = true;
if (confirmation === password) {
document.querySelector("#submit").disabled = false;
}
}
}
}
else {
document.querySelector('#submit').disabled = true;
}
}
</script>
{% endblock %}
Here is the output of my console:
* Serving Flask app "application.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [13/Dec/2020 19:23:44] "GET /signup HTTP/1.1" 200 -
127.0.0.1 - - [13/Dec/2020 19:23:44] "GET /static/styles.css HTTP/1.1" 200 -
Opened database successfully
Error in sign up operation
So the problem lies in signup.py
The try/except block is not doing you any favors. It can error on any line and all you'll know is "Error in signup operation". There will be problems because of invalid execute syntax. execute takes at most 2 arguments, the first is the sql to be executed. If it contains placeholders, the second argument is a set. Since these sqls are using named style, the second argument should be a dictionary, as per this example from the doc.
# And this is the named style:
cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age})
You might consider "catching" the exception and adding more info to the message, something like:
except Exception as e:
print("Error in sign up operation: ",e)

can not call function into wtforms radio field

I am trying to call a regular function into RadioField - choices[()].
when i select a radio button on my web page and click submit button, i should get the result from from function. my function says to print("Hi").
currently it print's the data on given value like 'value_one' when i select description.
So, i need a way to do call function to choices[('')].
below is my code
from flask import Flask, render_template
from flask_wtf import Form
from wtforms import RadioField, SubmitField
app = Flask(__name__)
app.config.from_object(__name__)
app.secret_key = 'password'
def print_1():
print("Hi")
class SimpleForm(Form):
example = RadioField('Label', choices=[('value_one','description'),('value_two','whatever')])
#app.route('/',methods=['post','get'])
def hello_world():
form = SimpleForm()
if form.validate_on_submit():
print(form.example.data)
else:
print(form.errors)
return render_template('form.html',form=form)
if __name__ == '__main__':
app.run(debug=True)
Below is my html code:
<form method="post">
{{ form.hidden_tag() }}
{{ form.example }}
<input type="submit" value="submit">
</form>

Field validation in WTF Forms Flask, redirect method

I am trying to create my first Flask web application and found the following problem, I have two pages, the first page should take players names and give the names to the next page, but unfortunately name validation does not work due to some reason, I can keep the required fields empty and go to next page with empty names fields.
Flask code:
class ChooseName(FlaskForm):
first_player_name = StringField("Choose first player name: ", [DataRequired()])
second_player_name = StringField("Choose second player name: ", [DataRequired()])
button = SubmitField("Confirm")
#app.route('/')
def index():
form = ChooseName()
if form.validate_on_submit():
return redirect(url_for('mega'))
return render_template('TIC_TAC_TOE_index.html', form=form)
#app.route('/game_page', methods=["GET", "POST"])
def mega():
player1 = request.args.get('first_player_name')
player2 = request.args.get('second_player_name')
......
return render_template('mega.html', form=form, error=error, x=x,
turn=turn,tornado=tornado, renew=renew, player1=player1,player2=player2)
HTML template:
<form action="{{url_for('mega')}}" method="get">
{{ form.hidden_tag() }}
<h4>Please choose players names!</h4>
{{form.first_player_name.label}} {{form.first_player_name}} <br> <br>
{{form.second_player_name.label}} {{form.second_player_name}} <br> <br>
{{form.button}} <br> <br>
</form>
Well looking at your function Mega(), you're not returning anything on the next page. You're just accepting the input but aren't returning it in any form.
from wtforms import Form, StringField, validators, SubmitField
from flask_wtf import FlaskForm
from flask import Flask, render_template, request
class ChooseName(FlaskForm):
first_player_name = StringField("Choose first player name: ", [validators.DataRequired()])
second_player_name = StringField("Choose second player name: ", [validators.DataRequired()])
button = SubmitField("Confirm")
app = Flask(__name__)
app.config['SECRET_KEY'] = "IT_IS_SECRET"
#app.route('/')
def index():
form = ChooseName()
if form.validate_on_submit():
return redirect(url_for('mega'))
return render_template('TIC_TAC_TOE_index.html', form=form)
#app.route('/game_page', methods=["GET", "POST"])
def mega():
player1 = request.args.get('first_player_name')
player2 = request.args.get('second_player_name')
return player1 + ' ' + player2
if __name__ == '__main__':
app.run(port=5000,debug=True)
Try to run this code, I hope this helps. :-)
This is because your action is pointing to the mega view, so the code from index if form.validate_on_submit(): is not being executed.
You should change the action attribute and method in your form. The code should be as follows:
HTML template:
<form action="" method="post">
{{ form.hidden_tag() }}
<h4>Please choose players names!</h4>
{{form.first_player_name.label}} {{form.first_player_name}} <br> <br>
{{form.second_player_name.label}} {{form.second_player_name}} <br> <br>
{{form.button}} <br> <br>
</form>
Views:
from flask import session
#app.route('/')
def index():
form = ChooseName()
if form.validate_on_submit():
session['first_player_name'] = form.first_player_name.data
session['second_player_name'] = form.second_player_name.data
return redirect(url_for('mega'))
return render_template('TIC_TAC_TOE_index.html', form=form)
#app.route('/game_page', methods=["GET", "POST"])
def mega():
player1 = session.pop('first_player_name')
player2 = session.pop('second_player_name')
......
return render_template('mega.html', form=form, error=error, x=x,
turn=turn,tornado=tornado, renew=renew, player1=player1,player2=player2)
You can learn more about WTForms here https://j2logo.com/tutorial-flask-leccion-3-formularios-wtforms/

How to redirect users to the required html page only after successful login (Flask Python App)?

I am trying to set up login page before accessing any other page. So as of now the code is working fine but if I access '/home' its taking directly to that page without login required page.
I tried to understand online solutions like login-required with SQLAlchemy but nothing seems working and I got totally lost. This does not require login-required I guess.
Here's my code:
from dbscriptdeploy import dbupdate
from flask.templating import render_template
from flask import Flask, request, url_for, redirect
DBupdate = dbupdate()
app = Flask(__name__) #create the Flask app
#app.route('/success')
def deploy_success():
return render_template("success.html")
def deploy_script(sql):
res = DBupdate.dbvalues_get(sql)
return res
#app.route('/', methods=['GET', 'POST'])
def login_page():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentials. Please try again.'
else:
return redirect(url_for('form_example'))
return render_template('login.html', error=error)
#app.route('/home', methods=['GET', 'POST'])
def form_example():
res = None
error = ''
try:
if request.method == 'POST':
sql = request.form.get('sql')
res = deploy_script(sql)
if res:
return redirect(url_for('deploy_success'))
else:
error = "*Invalid Value. Please try again."
return render_template('home.html', error=error)
except Exception as e:
return render_template('home.html', error=error)
if __name__ == '__main__':
app.run(debug=True) #run app in debug mode on port 5000
Login.html Code:
<html>
<head>
<title>Flask Intro - login page</title>
</head>
<body>
<div class="container">
<h1>Please login</h1>
<br>
<form action="" method="post">
<input type="text" placeholder="Username" name="username" value="{{
request.form.username }}">
<input type="password" placeholder="Password" name="password" value="{{
request.form.password }}">
<input class="btn btn-default" type="submit" value="Login">
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>
So what I expect is after successful login only then they should be directed to \home page else they should be directed again to login page.
If I were you, I'd use flask-login. However, if you want to develop a simple solution by your own, you should save some var in the user's session.
Also in your login method there is a bug. I'd do:
from flask import session
#app.route('/', methods=['GET', 'POST'])
def login_page():
error = None
if request.method == 'POST':
if request.form['username'] == 'admin' and request.form['password'] == 'admin':
session['admin'] = request.form['username']
return redirect(url_for('form_example'))
else:
error = 'Invalid Credentials. Please try again.'
return render_template('login.html', error=error)
Then, in your form_example view you should check that admin is in session, else you can redirect to your login view:
#app.route('/home', methods=['GET', 'POST'])
def form_example():
if 'admin' not in session:
return redirect(url_for('login_page'))
else:
# Your code here
If you really want to go down the path of developing your own login/authentication solution, check out the documentation for flash_message
http://flask.pocoo.org/docs/1.0/patterns/flashing/. This tutorial has the exact problem you're tackling.
The re-routing of a successful login attempt occurs with the redirect call
return redirect(url_for('homepage'))

Resources