Issue with passing variable through query string with Flask - python

I have a flask route that sends a variable as a query string when it is processed (i have a default of None, because the first time this template is rendered no token is needed, or passed) :
#app.route('/results/', methods=['GET', 'POST'], defaults={'token': None})
#app.route('/results/<token>', methods=['GET', 'POST'])
def results(token):
tags = request.form['text'].replace(' ', '').split(',')
data = fetch_data(tags=tags, next_page_token=token)
processed_data, token = process_data(data=data, tags=tags)
return render_template('results.html', data=processed_data[:1], token=token)
this is the template:
<!DOCTYPE html>
<html>
<body style="background-color:powderblue;">
<h1>{{ data }}</h1>
<form action="{{ url_for('results', token=token) }}">
<input type="submit" value="More results plz" />
</form>
</body>
</html>
For some reason when I click the submit button I get a 400 error 10.51.50.1 - - [13/Jul/2017 18:00:45] "GET /results/J0HWWe1OgAAAF0HWWey_wAAAFoAKAA%253D%253D? HTTP/1.1" 400
and this loads on the page
Bad Request
The browser (or proxy) sent a request that this server could not understand.
I think part of the issue is that the ? is after the token i'm passing through, but i'm not sure why. Also when i try to print request.args I don't get anything.
Any thoughts on how to properly send the token back to the route?

You have this line in your view function:
request.form['text']
but I can't find a <input> in your template named text.

Related

Create API with Flask that receives 2 strings and returns the similarity between them with spacy [duplicate]

This question already has answers here:
Passing HTML to template using Flask/Jinja2
(7 answers)
Closed 4 months ago.
I have this code that compute the similarity between 2 strings:
import spacy
from spacy.lang.pt.examples import sentences
X ="some string 1"
Y ="some string 2"
nlp = spacy.load('pt_core_news_sm')
X_nlp = nlp(X)
Y_nlp = nlp(Y)
token_x = [token.text for token in X_nlp]
token_y = [token.text for token in Y_nlp]
print("Similarity:", X_nlp.similarity(Y_nlp))
Now I want to transform this code in an API with flask, I tried to follow a tutorial:
from flask import Flask,render_template,url_for,request
import re
import spacy
from spacy.lang.pt.examples import sentences
nlp = spacy.load('pt_core_news_sm')
app = Flask(__name__)
#app.route('/',methods=["POST"])
def process():
X_nlp = nlp(input())
Y_nlp = nlp(input())
print("Similarity:", X_nlp.similarity(Y_nlp))
if __name__ == '__main__':
app.run(debug=True)
the code above returns: "GET / HTTP/1.1" 405 -
You are trying to reach the URL "/". However, within your code there is no route defined for this path. Thus, the error 404 is returned.
You need a route that accepts both a GET and a POST request to both display a form and receive data from a submitted form sent via POST.
Otherwise, a 405 error is returned because the request method is not allowed.
#app.route('/', method=['GET', 'POST'])
def index():
if request.method == 'POST':
# Handle a POST request and the data sent here.
# ...
Within Flask it is not possible to request input with input().
As mentioned above, you need a form within an HTML page. Within this form you can define input fields that must be provided with a name attribute in order to query them on the server side.
<form method="POST">
<input type="text" name="x" />
<input type="text" name="y" />
<input type="submit">
</form>
If the submit button is now pressed, the data of the form, as defined in the method attribute, is sent to the server via POST and can be queried here. The input fields are queried using the name attribute.
Finally, the endpoint must have a return value. In your case, this is the template that displays the page with the form and outputs the possible result.
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
x = request.form.get('x', '')
y = reutest.form.get('y', '')
# ...
return render_template('index.html')
So the entire code of your application should look something like this.
Flask (app.py)
from flask import (
Flask,
render_template,
request
)
import spacy
nlp = spacy.load('pt_core_news_sm')
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# Handle a POST request and the data sent here.
x_nlp = nlp(request.form.get('x', ''))
y_nlp = nlp(request.form.get('y', ''))
resultado = x_nlp.similarity(y_nlp)
# Return a rendered template and pass defined variables to the template.
return render_template('index.html', **locals())
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index</title>
</head>
<body>
<form method="POST">
<input type="text" name="x" />
<input type="text" name="y" />
<input type="submit">
</form>
{% if resultado -%}
<p>Similaridade: {{ resultado }}</p>
{% endif -%}
</body>
</html>

Setting Authorization header - Flask app using Python Requests and JWT

I am just learning to code and this has been driving me crazy. I don't know if I am missing something very simple or have a total misunderstanding about how authentication works (very possibly both), however, i would appreciate someone help.
I have created a login route for my flask app which renders the following and successfully allows a user logging in.
Login Page
If a user successfully logs in, i want to set the Authorization header using a token generated using JWT. I am using the request libary to do this and get a 200 response but everytime i check the network tab, i can not see the token in the 'Authorization' Response Header.
The idea is that once this Header has been set, i can protect my apis by ensuring a token is present and also use that information to ensure that APIs only return data for that user i.e. decrypt the token to work out the user.
Network tab - No Authorization Header
This is my current code. Where am i going wrong? Does my approach sound correct?
#loginsBlueprint.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
user = User.query.filter_by(username=request.form['username']).first()
if user is not None and bcrypt.check_password_hash(user.password, request.form['password']):
token = jwt.encode(
{'user': request.form['username'], 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=15)},
app.config['SECRET_KEY'])
url = 'http://127.0.0.1:5000/login'
headers = {'Authorization': 'Bearer ' + token}
requests.get(url, headers=headers)
return render_template('landing_page.html')
else:
return make_response('Could not verify', 403,
{'WWW-Authenticate': 'Basic realm ="Wrong Password !!"'})
return render_template('login.html', error=error)
login.html
<html>
<head>
<title>Flask Intro - login page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</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>
Note: I have tried changing to requests.post but get a 400:
127.0.0.1 - - [30/Mar/2021 21:53:29] "←[31m←[1mPOST /login HTTP/1.1←[0m" 400
I thought it might be because i'm using CORS and so added this in:
CORS(app, expose_headers='Authorization')
A few things which are confusing here:
In the login() method, you make a requests.get() call. So it looks like you're calling a new endpoint from your app. Is that how it should work? To be exact, you seem to check the user's credentials, issue a JWT and then call the /login endpoint of an app listening on port 5000, setting the JWT as the bearer token.
Authorization is a request header. You don't use it in responses to the client. If you want to return the JWT to the client use one of the OAuth flows, either the Code flow (preferably) or the Implicit flow.
Once you'll get the token to your client, then you should use it as you said - set in the Authorization header as a Bearer token. As you're using flask, you can use this filter to secure your APIs.

Flask - 400 Bad request

I have this python code which should take in data from an html form and use it in a WHERE clause:
#app.route('/search', methods=['GET'])
def search():
connect = cx_Oracle.connect("benjamin", "siliyetu", "PRINCE-PC/XE")
cursor = connect.cursor()
searched = request.form['search']
named_params = {'search':searched}
query = cursor.execute("SELECT * FROM edited WHERE REGEXP_LIKE (cod_ed,
:search) OR REGEXP_LIKE (nome_ed,:search) OR
REGEXP_LIKE (endereco,:search) OR REGEXP_LIKE
(telefone,:search) OR REGEXP_LIKE
(cidade,:search)", named_params)
results = cursor.fetchall()
posts = list(results)
return render_template('search.html', posts=posts)
and the template I'm using is this(part of the template anyway. Its not the whole thing):
<form method="POST" action="/editora" class="form-outline" >
<div class="col-lg-7 col-offset-6 right">
<div class="form-group mx-lg-3 mb-2">
<label for="element-7" ></label>
<input id="search" name="search" type="text" class="form-control" placeholder="Pesquisar..." />
<label></label>
<a class="btn btn-primary " type="submit" href="search">Pesquisa</a>
When I try to use the data from the form, it gives me a
werkzeug.exceptions.HTTPException.wrap.<locals>.newcls: 400 Bad Request: KeyError: 'search'
But when I input data using input() it works fine. What gives!?
How would I go about fixing this issue? I also want to add some regular expressions in the where clause but its not budging. How do I do that too?
Ps- I'm working with oracle express edition 11g
Without having a traceback (you are running with the debug server while developing, right?), the exception you're getting comes from the
searched = request.form['search']
line.
the HTML example you have POSTs to /editora
the Python code you have has a route /search (not /editora) and the view won't accept POST requests anyway (methods=['GET']).
Are you sure the snippets you've posted are correct?
request.form is only populated for POST requests, anyway.
If you want to submit data to search route, you form action should point to that route.
<form method="POST" action="/search" class="form-outline" >
And if you want for a search route to get that data from POST request, you should put in methods 'POST' value.
#app.route('/search', methods=['GET', 'POST'])
The reason why you get:
werkzeug.exceptions.HTTPException.wrap.<locals>.newcls: 400 Bad Request: KeyError: 'search'
because you are sending something to the application or server that they cannot handle. (http://werkzeug.pocoo.org/docs/0.14/exceptions/#werkzeug.exceptions.BadRequest)
KeyError is for trying to access dict object parameter 'search' which doesn't exist beucase form is never submited.

Redirecting User To Non Coded URL

Our app POSTS user data and then get's a success or rejected response. The success response will come with a URL like such:
b'SUCCESS|http://examplesite.com/m.cfm?t=17&wm_login=info&gouser=50105E5C440'
The issue is when I split this data in python to so I can send users to the URL python encodes this URL so it no longer works.
There is no server error message but rather the error is apparent in the redirect URL:
http://examplesite.com/m.cfm?t=17&wm_login=info&gouser=50105E5C440
Notice the & gets converted to &
I have tried contless solution to similar problems but nothing seems to redirect the user to an uncoded URL. The part that get's me is that when I print() the redirect URL it actually shows the right one!
The reason I redirect to a page first is that this form is an iframe and otherwise the Parent page does not get redirected.
views.py
def iframe1(request):
ip = get_real_ip(request)
created = timezone.now()
if request.method == 'POST':
form = LeadCaptureForm1(request.POST)
if form.is_valid():
# Save lead
lead = form.save(commit=False)
lead.created = created
lead.birth_date = form.cleaned_data.get('birth_date')
lead.ipaddress = get_real_ip(request)
lead.joinmethod = "Iframe1"
lead.save()
# API POST and save return message
payload = {
...
}
r = requests.post(url, payload)
print(r.status_code)
print(r.content)
api_status1 = r.content.decode("utf-8").split('|')[0]
api_command1 = r.content.decode("utf-8").split('|')[1]
print(api_status1)
print(api_command1)
#backup_link = "https://govice.online/click?offer_id=192&affiliate_id=7&sub_id1=API_Backup-Link"
backup_link = "http://viceoffers.com"
lead.xmeets = r.content
lead.save()
# Redirect lead to Success URL
if "http" in api_command1:
return TemplateResponse(request, 'leadwrench/redirect_template.html', {'redirect_url': api_command1, 'api_status1': api_status1})
else:
return TemplateResponse(request, 'leadwrench/redirect_template.html', {'redirect_url': backup_link})
redirect_template.html
<html>
<head>
<meta http-equiv="refresh" content="5; url={{ redirect_url }}" />
<script>
window.top.location.href = '{{ redirect_url }}';
</script>
</head>
<body>
<p>api_status1: {{ redirect_url }}</p>
<p>api_command1: {{ api_command1 }}</p>
</body>
</html>
By default, Django will do HTML escaping of template arguments, which (among other things) changes & to &. Use the safe template filter in your template to avoid that:
<html>
<head>
<meta http-equiv="refresh" content="5; url={{ redirect_url|safe }}" />
<script>
window.top.location.href = '{{ redirect_url|safe }}';
</script>
</head>
<body>
<p>api_status1: {{ redirect_url }}</p>
<p>api_command1: {{ api_command1 }}</p>
</body>
</html>

Flask: How to handle application/octet-stream

I want to make a multiple file-upload form.I use jQuery File Uploader. My server-side code:
#app.route("/new/photogallery",methods=["POST"])
def newPhotoGallery():
print request.files
I tried two things:
Submit form normally:
When i submit my form normally,it prints:
ImmutableMultiDict([('post_photo_gallery', FileStorage: u'' ('application/octet-stream'))])
Submit form using AJAX:
When i submit my form using AJAX,it prints:
ImmutableMultiDict([])
My first question is: Why is there a difference between AJAX request and normal request.
My second question is: How can i handle this application/octet-streamrequest in Flask/Python
My third question is: Is this a good way to use application/octet-stream ?
By the way i do not know much about application/octet-stream.Thank you very much.
Regardless of the the data encoding, you should be able to get the raw data with request.data.
In the case of application/octet-stream, you can just write request.data to a binary file.
An example handler for various data types:
from flask import json
#app.route('/messages', methods = ['POST'])
def api_message():
if request.headers['Content-Type'] == 'text/plain':
return "Text Message: " + request.data
elif request.headers['Content-Type'] == 'application/json':
return "JSON Message: " + json.dumps(request.json)
elif request.headers['Content-Type'] == 'application/octet-stream':
with open('/tmp/binary', 'wb') as f:
f.write(request.data)
f.close()
return "Binary message written!"
else:
return "415 Unsupported Media Type ;)"
The typical scenario of handling form data is already documented here.
I was unable to get a request working using application/octet-stream type posts, but have used multipart/form-data type forms in the past to upload images using flask.
I have extended what I have done in the past to support multiple upload files and this has worked leveraging werkzeug's FileStorage objects.
The key here is setting up a post based route that is looking for a request element from a form. This should allow you to POST to the route either via a standard form or an AJAX call.
Below is a simplified example that is using a form:
Template for the view:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
</head>
<body>
{% if err %}
<h4>{{ err }}</h4>
{% endif %}
<form action="/" method=POST enctype=multipart/form-data id="fileupload">
<input type="file" name="files" data-url="/" multiple>
<input type=submit value=Post>
</form>
{% if files %}
{% for file in files %}
<p>Uploaded: <b>{{ file }}</b> </p>
{% endfor %}
{% endif %}
</body>
</html>
Flask App
from flask import Flask, request, render_template
from werkzeug import secure_filename, FileStorage
import os
# Flask functions
app = Flask(__name__)
app.config.from_object(__name__)
DEBUG = True
# add this so that flask doesn't swallow error messages
app.config['PROPAGATE_EXCEPTIONS'] = True
#app.route('/', methods=['GET', 'POST'])
def uploader():
if request.method =='POST' and request.files.getlist('files'):
up_file_list = []
# Iterate the through a list of files from the form input field
for a_file in request.files.getlist('files'):
if a_file.filename:
# Validate that what we have been supplied with is infact a file
if not isinstance(a_file, FileStorage):
raise TypeError("storage must be a werkzeug.FileStorage")
# Sanitise the filename
a_file_name = secure_filename(a_file.filename)
# Build target
a_file_target = os.path.join('/tmp/', a_file_name)
# Save file
a_file.save(a_file_target)
up_file_list.append(a_file_name)
# Return template
if up_file_list:
return render_template('uploader.html', err=None, files=up_file_list)
else:
return render_template('uploader.html', err='No Files Uploaded', files=None)
else:
return render_template('uploader.html', err=None, files=None)
# application execution
if __name__ == '__main__':
app.run()

Categories

Resources