using flask_wtf.csrf without wtf_forms - python

I have a simple flask web app and I want to use flask_wtf csrf protection but whenever I try to run to submit the form I get an error saying I am missing the CSRF token.
Is it even possible to use csrf without wtf forms?
and if so what am I doing wrong?
my code:
app = Flask(__name__)
csrf = CSRFProtect(app)
#app.route("/reserve", methods=["GET", "POST"])
def reserve():
if request.method == "GET" :
return render_template("reserve.html", **context)
<form id="Reserve" action="/reserve" method="post">
<!-- csrf protection -->
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<input type="text" placeholder="Name">
<button type="submit">
Submit
</button>
</form>

Looking your code, you need to init app with csfr, an example below:
from flask_wtf.csrf import CSRFProtect
from flask import Flask,render_template,request,redirect
app = Flask(__name__)
csrf = CSRFProtect(app)
csrf.init_app(app)
app.config['SECRET_KEY'] = 'SUPER SECRET KEY TEST'
#app.route("/reserve", methods=["GET", "POST"])
def reserve():
context = {
'gh':'as'
}
if request.method == "GET" :
return render_template("reserve.html", **context)
else:
user = request.form['ssss']
return 'USER : '+user
#app.route("/")
def index():
return redirect('/reserve')
and html
<form id="Reserve" action="/reserve" method="post">
<!-- csrf protection -->
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<input type="text" placeholder="Name" name='ssss'>
<button type="submit">
Submit
</button>
</form>

Related

plagiarism detector python flask error method not found

I am developing a plagiarism detection tool using flask and python and I am getting the error "Method Not Allowed The method is not allowed for the requested URL.". The project allows a user to upload two files to be compared. Whenever I click on the submit button in the html form then the above error occurs. Can you please suggest some changes?
from io import FileIO
from flask import Flask
from flask import render_template
from flask import request
from flask.helpers import url_for
from werkzeug.utils import redirect, secure_filename
import os
import numpy as np
app=Flask(__name__)
#app.route("/")
def home():
return render_template('upload.html')
#app.route("/upload", methods=["GET", "POST"])
def upload():
if request.method == "POST":
f1 = request.files['file1']
f2 = request.files['file2']
return redirect(url_for('user'))
else:
return render_template('upload.html')
#app.route("/")
def user():
return f"<h1>success</h1>"
if __name__=='__main__':
app.run(debug=True)
my html code snippet from upload.html is:
<form enctype="multipart/form-data" method="post">
<label for="file1">Upload first file here:</label>
<input type="file" id="file1" name="file1"><br><br>
<label for="file2">Upload second file here:</label>
<input type="file" id="file2" name="file2"><br><br>
<input type="submit" value="Submit">
</form>
You're missing an action in your form. In your implementation, it tries to send a POST request to home(), not upload(). That's why you're getting Method not allowed message.
<form action="/upload" enctype="multipart/form-data" method="post">
<label for="file1">Upload first file here:</label>
<input type="file" id="file1" name="file1"><br><br>
<label for="file2">Upload second file here:</label>
<input type="file" id="file2" name="file2"><br><br>
<input type="submit" value="Submit">
</form>

form action in flask not redirecting to the route

Simply I am just trying to redirect to an url by using the below code in my login.html template:
<form>
<form action="/sessions">
<p>Username:</p>
<p><input type="text" minlength="8" name="username"required /></p>
<p>Password:</p>
<p><input type="text" name="password"/></p>
<input type="submit" value="Submit">
</form>
and
def login():
print("inside login")
return render_template('login.html')
#app.route("/sessions", methods=["GET","POST"])
def sessions():
userid = request.form.get("userid")
password = request.form.get("password")
return request.form.get("userid"), request.form.get("password")
but is stuck on the login() url. Also I tried
<form action="{{ url_for('sessions') }}">
but is not working as well. Not sure what I am missing? Please any hints/ideas would be highly appreciated.
Try this ( i just added one more line, the commented one):
#app.route("/sessions", methods=["GET","POST"])
def sessions():
userid = request.form.get("userid")
password = request.form.get("password")
if request.method == 'POST': #additional line
return request.form.get("userid"), request.form.get("password")
Updated answer reflects new comments
Found couple issues in your code:
HTML form is incorrect, you are using form in form
<form>
<form action="/sessions">
<p>Username:</p>
<p><input type="text" minlength="8" name="username"required /></p>
<p>Password:</p>
<p><input type="text" name="password"/></p>
<input type="submit" value="Submit">
</form>
You should change it to this
<html>
<body>
<h1>This is login page</h1>
<form action="{{ url_for('login') }}" method="POST">
<p>Username:</p>
<p><input type="text" minlength="8" name="username"required /></p>
<p>Password:</p>
<p><input type="text" name="password"/></p>
<input type="submit" value="Submit">
</form>
</body>
</html>
Notice changes, first there is only 1 form tag, then I use jinja2 engine to call the login in form.action, 2nd this login page handles serving login HTML when there is a GET request (initially opening this page) and for accepting form POST request with credentials.
Then I changed the routes to this:
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
user_name = request.form['username']
password = request.form['password']
print(user_name, password) # do something here?
return redirect(url_for('session'))
return render_template('login.html')
#app.route('/session')
def session():
return render_template('session.html')
Notice that now login accepts both methods, GET and POST, as mentioned before, GET is for serving HTML content and POST is for submitting form data. In the login endpoint I have a condition that checks, if it's a POST method request, then I extract credential details from request.form and after doing something (e.g. in that print() statementIreturn redirect(url_for('session'))`.
This is how you manage redirects from one page to another by clicking submit on one of a pages.
original answer that was incorrect
In Flask to redirect, you could you something like this:
from flask import url_for, redirect
#app.route('/sessions', methods['GET', 'POST']
def sessions():
# some code
return redirect(url_for('some.endpoint'))
This will redirect you to a specific endpoint that you will provide. In the docs there is more info about it.

HTML form (python, flask): have a button submit a unique parameter to method

I have a good HTML form right now that calls a method via a button.
What I want to do is create several new buttons that call the same method, but each pass a different parameter.
The specific use case is: my button right now retrieves a random album with get_random_album().
I want to make a "Jazz", "Classical", and "Rock" buttons that respectively call get_random_album(genre=<genre>).
MVE:
from flask import Flask,redirect
# Below import commented out for MVE
# from discogs import get_random_album
# TODO: look at more advanced form builders
# Create app instance
app = Flask(__name__)
# Create homepage with button
#app.route("/")
def home():
return """
<html><body>
<h2> Spin yo records </h2>
<form action="/query">
<input type='submit' value="I'm Feeling Lucky">
</body></html>
"""
# Backend query to discogs
#app.route("/query")
def link():
# return redirect(get_random_album())
# Real implementation commented out
# Scratch implementation here
def get_random_album(genre=None):
url = "https://www.google.com"
if genre == 'Jazz':
return url + "/search?q=jazz"
if genre == 'Classical':
return url + "/search?q=classical"
if genre == 'Rock':
return url + "/search?q=rock"
return url
return redirect(get_random_album())
# Run app
if __name__ == "__main__":
app.run(debug=True,port=600)
Actual project
First create buttons with the same name but with different value
#app.route("/")
def home():
return """
<html>
<body>
<h2> Spin yo records </h2>
<form action="/query">
<input type="submit" name="selected_genre" value="Jazz">
<input type="submit" name="selected_genre" value="Classic">
<input type="submit" name="selected_genre" value="Rock">
<input type="submit" name="selected_genre" value="I'm Feeling Lucky">
</form>
</body>
</html>
"""
And next you can get selected value using request and name used in buttons
from flask import request
import random
#app.route("/query")
def link():
allowed_values = ('Jazz', 'Classic', 'Rock')
genre = request.args.get("selected_genre")
# "I'm Feeling Lucky"
if genre not in allowed_values:
genre = random.choice(allowed_values)
genre = genre.lower()
url = f"https://www.google.com/search?q={genre}"
return redirect(url)
Full example
from flask import Flask, redirect, request
import random
app = Flask(__name__)
#app.route("/")
def home():
return """
<html>
<body>
<h2> Spin yo records </h2>
<form action="/query">
<input type="submit" name="selected_genre" value="Jazz">
<input type="submit" name="selected_genre" value="Classic">
<input type="submit" name="selected_genre" value="Rock">
<input type="submit" name="selected_genre" value="I'm Feeling Lucky">
</form>
</body>
</html>
"""
#app.route("/query")
def link():
allowed_values = ('Jazz', 'Classic', 'Rock')
genre = request.args.get("selected_genre")
if genre not in allowed_values:
genre = random.choice(allowed_values)
genre = genre.lower()
url = f"https://www.google.com/search?q={genre}"
return redirect(url)
if __name__ == "__main__":
app.run(debug=True,port=600)
In previous version it sends value in url ie. /query?selected_genre=Rock - so everyone can see it or easily it can try to use own value. And this is why I used allowed_values to block it.
To hide selected genre from url you have to use:
<form ... method="POST">
#app.route(..., methods=['GET', 'POST']) (or methods=['POST'])
request.form instead of request.args
Full example
from flask import Flask, redirect, request
import random
app = Flask(__name__)
#app.route("/")
def home():
return """
<html>
<body>
<h2> Spin yo records </h2>
<form action="/query" method="POST">
<input type="submit" name="selected_genre" value="Jazz">
<input type="submit" name="selected_genre" value="Classic">
<input type="submit" name="selected_genre" value="Rock">
<input type="submit" name="selected_genre" value="I'm Feeling Lucky">
</form>
</body>
</html>
"""
#app.route("/query", methods=['GET', 'POST'])
def link():
allowed_values = ('Jazz', 'Classic', 'Rock')
genre = request.form.get("selected_genre")
if genre not in allowed_values:
genre = random.choice(allowed_values)
genre = genre.lower()
url = f"https://www.google.com/search?q={genre}"
return redirect(url)
if __name__ == "__main__":
app.run(debug=True, port=600)
If you want to use different text on button but still send the same value then you may need hidden <input> with value but then every button will need seprated <form>
#app.route("/")
def home():
return """
<html>
<body>
<h2> Spin yo records </h2>
<form action="/query" method="POST">
<input type="hidden" value="Jazz" name="selected_genre">
<input type="submit" value="The Best Jazz Music">
</form>
<form action="/query" method="POST">
<input type="hidden" value="Classic" name="selected_genre">
<input type="submit" value="The Best Classic Music">
</form>
<form action="/query" method="POST">
<input type="hidden" value="Rock" name="selected_genre">
<input type="submit" value="The Best Rock Music">
</form>
<form action="/query" method="POST">
<input type="hidden" value="random" name="selected_genre">
<input type="submit" value="I'm Feeling Lucky">
</form>
</body>
</html>
"""
Or you have to use <button> instead of <input>
#app.route("/")
def home():
return """
<html>
<body>
<h2> Spin yo records </h2>
<form action="/query" method="POST">
<button type="submit" name="selected_genre" value="Jazz">The Best Jazz Music</button>
<button type="submit" name="selected_genre" value="Classic">The Best Classic Music</button>
<button type="submit" name="selected_genre" value="Rock">The Best Rock Music</button>
<button type="submit" name="selected_genre" value="random">I'm Feeling Lucky</button>
</form>
</body>
</html>
"""

Routing on Flask-appbuilder - build Error

Trying to load my homepage and getting build error, that it cant build the url for the endpoint 'Myview.general', this was working fine for 2 months before today,
view.py
class Myview(BaseView):
route_base = "/home"
#has_access
#expose('/general', methods=['GET', 'POST'])
#appbuilder.app.route('/general', methods=['GET', 'POST'])
def general(self):
if request.method == 'POST':
bucket = request.form['bucket']
session['bucket'] = bucket
return redirect(url_for('HomeView.files'))
else:
buckets = get_buckets_list()
return render_template(
'index.html',
base_template=appbuilder.base_template,
appbuilder=appbuilder,
buckets=buckets
)
HTML Snippet
<form class="select-bucket" action="{{ url_for('HomeView.general')}}" method="post">
<input type="hidden" name="bucket" value="{{ bucket['Name'] }}"/>
<button type="submit" class="btn btn-primary btn-sm">
<i class="fa fa-folder-open"></i>
</button>
</form>

Post values from an HTML form and access them in a Flask view

I have an HTML form that gets posted to a Flask route. However, request.form is empty. If I try to access one of the values by id, I get a 400 error. How do I post values from an HTML form and access them in Flask?
<form method="POST">
<input id="my_input" type="text" value="{{ email }}">
<input id="my_submit" type="submit" value="Submit">
</form>
#app.route('/page', methods=['POST', 'GET'])
def get_page():
if request.method == 'POST':
print(request.form) # prints ImmutableMultiDict([])
print(request.form['my_input']) # raises 400 error
return render_template('page.html')
Your input doesn't have a name attribute. That is what the client will pass along to the server. Flask will raise a 400 error if you access a form key that wasn't submitted.
<input name="my_input" id="my_input" type="text" value="{{ email }}">
You need to Specify the form Action method in the Html page, and then mention the HTML Text box name inside the Tag.
<form method="POST" action="/PythonFunctionName">
<input id="my_input" type="text" name="HTMLControlName" value="{{ email }}">
<input id="my_submit" type="submit" value="Submit">
</form>
And inside the .py module access the element using the name specified in the HTML tag.
#app.route('/PythonFunctionName', methods=['POST', 'GET'])
def getPage():
if request.method == 'POST':
strTextBoxVal= request.form['HTMLControlName'])
Print(strTextBoxVal)
return render_template('page.html')

Categories