Routing on Flask-appbuilder - build Error - python

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>

Related

using flask_wtf.csrf without wtf_forms

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>

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>
"""

where am gonna wrong with search?

views.py
def userlogout(request):
logout(request)
return HttpResponseRedirect(reverse('userlogin'))
def Search(request):
if request.method == 'POST':
search=request.GET['srch']
if search:
match=Blog.objects.filter(Q( blog_title_icontains=search)|
Q( blog_description_icontains=search)|
Q(blogcategories_icontains=search) )
if match:
return render (request,"search.html",{"sr":match})
else:
messages.error(request,"no results found")
else:
return HttpResponseRedirect('/search/')
return render (request,'index.html')
#
index.html
<form action="{%url 'search' %}" method="post" class="form-inline my-2 my-lg-0 header-search">
{% csrf_token %}
<input class="form-control mr-sm-2" type="search" placeholder="Search here..." name="Search" required="">
<button class="btn btn1 my-2 my-sm-0" type="submit">
<i class="fas fa-search"></i>
</button>
</form>
blog/urls.py
path('search/', views.Search, name='search'),
*****it gives me error:
Exception Type: MultiValueDictKeyError
Exception Value:
'srch'
please help me how can i search in my blog by using existing template.
You have several errors.
Your search field is called Search, not srch. I don't know where you got srch from since you never use it in the template.
Your form is being submitted by POST, but you are trying to get the data from the GET.
But in fact a search form should be submitted by GET, not POST, since it is not making changes in the backend and could conceivably be cached.
So you need:
<form action="{%url 'search' %}" method="get" class="form-inline my-2 my-lg-0 header-search">
...
def Search(request):
search=request.GET['Search']
if search:

Getting None from request.form.get()

I need to get data from 2 different forms. The first "index.html" rendering takes a user's selected option and stores it on the variable "item".
on "page2.html", the "item" value is shown here just fine. And again, the user is entering some new data on the textbox input and then it's redirected to the next rendering, "page3.html"
on "page3.html", it is supposed to show both data from the forms on "index.html" and "page2.html" but i'm getting "None" when I try to show the "item" value. Why?
I've tried to do it on separate app.route() routes, but I got the None type value as well.
the app.py file:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/", methods=['GET', 'POST'])
def index():
if request.method == 'POST':
if request.form.get('send') == 'send':
item = str(request.form.get('test1'))
return render_template('page2.html', item=item)
if request.form.get('send2') == 'send2':
item = str(request.form.get('test1'))
text = request.form.get('textbox')
return render_template('page3.html', item=item, text=text)
else:
return render_template('index.html')
app.run(debug=True)
the index.html file:
<div align="center">
<form method="POST" action="{{ url_for('index') }}">
<select name="test1">
<option name="1" value="1">1</option>
<option name="2" value="2">2</option>
<option name="3" value="3">3</option>
</select>
<button type="submit" name="send" value="send">Send</button>
</form>
</div>
the page2.html file:
<div align="center">
<form method="POST" action="{{ url_for('index') }}">
<h2>Previous selection: {{ item }}</h2><br>
<input type="text" name="textbox" value="Enter text">
<button type="submit" name="send2" value="send2">Send</button>
</form>
</div>
and the page3.html file:
<div align="center">
<h2>Your result is:</h2><br>
<h2>"{{ text }}" and "{{ item }}" </h2>
</div>
store the value of item in a session so that you can access it later. Once you are done you can clear the session like session.pop("session_name", None)
if request.form.get('send') == 'send':
item = str(request.form.get('test1'))
session["test1"]=item
return render_template('page2.html', item=item)
if request.form.get('send2') == 'send2':
item = session.get("test1")
text = request.form.get('textbox')
return render_template('page3.html', item=item, text=text)

TypeError: Object of type 'Response' is not JSON serializable

The function extract_data() converts uploaded PDF file to JSON data.
Function form_input() is meant to post the JSON data from "extract_data" as default input form values.
Extract_data() generates JSON data but is not redirecting it to form_input()
Below are the functions -
from flask import render_template, redirect, url_for, jsonify
from werkzeug.utils import secure_filename
#app.route("/", methods=["GET", "POST"])
def extract_data(input_module=pdftotext):
if request.method == "POST":
file = request.files["file"]
if file and allowed_file(file.filename):
invoicefile = secure_filename(file.filename)
extracted_str = input_module.to_text(invoicefile)
json_data=jsonify(ext)
session['json_data'] = json_data
return redirect(url_for('form_input', json_data=json_data)
return render_template("extract.html")
Here is extract.html
<html>
<form method='POST' enctype=multipart/form-data>
<input type="file" name="file" class="btn btn-success"></input>
<br>
<button type="submit" value=Upload class="btn btn-warning">Go!
</button>
</form>
</html>
The function form_input() is meant to get the json_data from extract_data() and use it as default form input values.
#app.route("/form_input")
def form_input():
json_data = request.args['json_data']
json_data = session['json_data']
if request.method == 'POST':
submited_item = request.POST['%s' % (value1)]
return render_template("inputdata.html", json_data="json_data")
Here is input_data.html:
<html>
<form method="POST">{{ csrf_token }}
<label>Input data</label>
<input type="text">
{% for item in json_data %}
<input type="checkbox" name="{{ item.value1 }}" value="{{ item.value1 }}"> {{ item.value1 }}<br>
{% endfor %}
<button type="submit" >Submit</button>
</form>
</html>

Categories