I am using cherrypy to run an interactive website and although the python function to generate the CSV seems to be working (if you interact with it directly, my browser downloads it), it does not seem to be giving the user this CSV file when I embed it in a form request:
<form id="export_csv_left" action="/c/flex_export_csv" method="get">
<input type="hidden" name="datakey" value="8TZbmRZ54IL7" >
<button type="button">Export stories and data as CSV</button>
</form>
I'd like there to be a button that says "export CSV" and return the file.
That form generates a request to my cherrypy that looks like this:
djotjog.com/c/flex_export_csv?datakey=8TZbmRZ54IL7
The headers inside the cherrypy part are...
csv = make_csv(literal_eval(raw_data), filename)
cherrypy.response.headers['Content-Type'] = "application/x-download"
cherrypy.response.headers['Content-Disposition'] = ('attachment; filename= %s' % (filename,))
return csv
And loading that link in the browser DOES generate the CSV. So what's up with the form stuff?
Here are some potentially relevant javascript console messages I don't really understand:
Denying load of chrome-extension://ganlifbpkcplnldliibcbegplfmcfigp/scripts/vendor/jquery/jquery.min.map. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
In case that's related.
Your issue has nothing to do with CherryPy per se. Just make sure your form button type attribute is submit and response content-type header is generic application/octet-stream (or text/csv). Like this.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 4
}
}
class App:
#cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<body>
<form action="/gimmefile" method="get">
<input type="hidden" name="key" value="8TZbmRZ54IL7"/>
<button type="submit">Export CSV</button>
</form>
</body>
</html>
'''
#cherrypy.expose
def gimmefile(self, key):
cherrypy.response.headers['Content-Type'] = 'application/octet-stream'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename=yourfile.csv'
return 'Your;file;content;and;{0}'.format(key)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
Related
I have the code below in my Python script:
def cmd_wui(argv, path_to_tx):
"""Run a web UI."""
from flask import Flask, flash, jsonify, render_template, request
import webbrowser
app = Flask(__name__)
#app.route('/tx/index/')
def index():
"""Load start page where you select your project folder
or load history projects from local DB."""
from txclib import get_version
txc_version = get_version()
prj = project.Project(path_to_tx)
# Let's create a resource list from our config file
res_list = []
prev_proj = ''
for idx, res in enumerate(prj.get_resource_list()):
hostname = prj.get_resource_host(res)
username, password = prj.getset_host_credentials(hostname)
return render_template('init.html', txc_version=txc_version, username=username)
Also, I have an HTML form in init.html:
<form>
<input type="text" id="projectFilepath" size="40" placeholder="Spot your project files">
<input type="button" id="spotButton" value="Spot">
</form>
How can I pass the user input from "projectFilepath" when a user clicks "spotButton" on a variable in my python script?
I'm new in Python and Flask, so forgive me if I make any mistakes.
The form tag needs some attributes set:
action: The URL that the form data is sent to on submit. Generate it with url_for. It can be omitted if the same URL handles showing the form and processing the data.
method="post": Submits the data as form data with the POST method. If not given, or explicitly set to get, the data is submitted in the query string (request.args) with the GET method instead.
enctype="multipart/form-data": When the form contains file inputs, it must have this encoding set, otherwise the files will not be uploaded and Flask won't see them.
The input tag needs a name parameter.
Add a view to handle the submitted data, which is in request.form under the same key as the input's name. Any file inputs will be in request.files.
#app.route('/handle_data', methods=['POST'])
def handle_data():
projectpath = request.form['projectFilepath']
# your code
# return a response
Set the form's action to that view's URL using url_for:
<form action="{{ url_for('handle_data') }}" method="post">
<input type="text" name="projectFilepath">
<input type="submit">
</form>
You need a Flask view that will receive POST data and an HTML form that will send it.
from flask import request
#app.route('/addRegion', methods=['POST'])
def addRegion():
...
return (request.form['projectFilePath'])
<form action="{{ url_for('addRegion') }}" method="post">
Project file path: <input type="text" name="projectFilePath"><br>
<input type="submit" value="Submit">
</form>
I am trying to understand an issue with Google App Engine and Python. It appears that I cannot have a POST handler in the MainPage class. Or, I am somehow using it incorrectly. The system does not object to the Python code but does not seem to find the post method. The response from the server is "405 Method Not Allowed" and "The method POST is not allowed for this resource. "
The output on the dev_appserver.py console is
INFO 2018-11-14 13:41:32,104 module.py:861] default: "GET / HTTP/1.1" 200 267
INFO 2018-11-14 13:41:35,550 module.py:861] default: "POST / HTTP/1.1" 405 188
The original source is
# -*- coding: utf-8 -*-
import webapp2
import logging
form = """
<form action="/" method="post">
<input type="checkbox" name="vehicle" value="Bike">Bike<br>
<input type="checkbox" name="vehicle" value="Car">Car<br>
<input type="submit" value="Submit" >
</form>
"""
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.write(form) # write the blank form
def post(self):
logging.info("in MainPage>post")
self.response.write("Thanks! That works !!!")
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
The GET method is invoked correctly and the simple form is displayed properly. The 405 error appears when I make a selection and submit the form. I have declared the form with both;
<form action="/" method="post">
and
<form method="post">
I can create an additional class that can contains a POST method and have action select the other class; everything works fine. I just have not found any logical reason it cannot correctly function in MainPage.
I am new to scrapy and in general web tech.
While working on a scrapy example to perform auto login. I came across 1 field , referrer url . I am wondering when do i need to this.
return scrapy.FormRequest.from_response(
response,
url='www.myreferrer.com', #when do i need this ???
formnumber=1,
formdata=self.data['formdata'],
callback=self.after_login
)
I tested with and without it and it works in both instances.
I understand that referrer url is for security but how do i determine from html code that i need or dont need this ?
ADDON
The following html form required the url to be defined :
<form id="login" enctype="multipart/form-data" method="post" action="https:///myshop.com/login/index.php?route=account/login">
I am a returning customer.<br>
<br>
<b>E-Mail Address:</b><br>
<input type="text" name="email">
<br>
<br>
<b>Password:</b><br>
<input type="password" name="password">
<br>
Forgotten Password<br>
<div style="text-align: right;"><a class="button" onclick="$('#login').submit();"><span>Login</span></a></div>
</form>`
class FormRequest(Request):
# delete some code here
#classmethod
def from_response(cls, response, formname=None, formid=None, formnumber=0, formdata=None,
clickdata=None, dont_click=False, formxpath=None, formcss=None, **kwargs):
url = _get_form_url(form, kwargs.pop('url', None))
def _get_form_url(form, url):
if url is None:
return urljoin(form.base_url, form.action)
return urljoin(form.base_url, url)
if the url is empty, it uses form tag's action attribute to get the URL.
if the url is not empty, then it use the URL you give to it.
the base_url comes from the response.
def _get_form(response, formname, formid, formnumber, formxpath):
"""Find the form element """
root = create_root_node(response.text, lxml.html.HTMLParser,
base_url=get_base_url(response))
so, when the action attribute does not exist or the login requests is not sent to the action URL, you need to pass the argument.
I am using Django 1.10 and python 3.4 on windows. I set up pdfkit and it works perfectly from command line. I want to use it in the site on a button to return the current page as a pdf attachment without redirecting anywhere(if possible). The page to convert is a report which uses a user specified date as url.
Currently the button redirects by appending the current url with "?mybtn=Generate+PDF#"
I have seen some solutions using jQuery or javascript, but I only really know python well. I will learn those eventually, but for now I would like a quicker solution where I understand what's going on.
views.py
class FlashReport(generic.View):
template_name = "reports_flash_report.html"
def get(self, request, year, month, day):
report_data = get_flash_report_data(int(year),int(month),int(day))
return render(request, 'reports_flash_report.html', report_data)
def generate_PDF(request):
path = request.get_full_path()
pdf = pdfkit.from_url(path, False)
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="flash_report.pdf"'
return response
reports_flash_report.html
<div>
<form action="" method="get">
<input type="submit" class="btn" value="Generate PDF" name="mybtn" />
</form>
</div>
urls.py
url(r'^flash_report/(?P<year>[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})/$', views.FlashReport.as_view(), name="flash_report"),
I am using python flask for a web application and I have following routes in my python file
#app.route("/admin", methods=['GET', 'POST'])
def admin():
print "In admin method. With request method: ", request.method
pass
#app.route("/<query>", methods=['GET'])
def search(query):
print "In search method. With request method: ", request.method
pass
My app is doing something very weird. I added print statements to know where the request goes through and in my admin.html file when I submit the form that looks like below
<script type="text/javascript">
$(document).ready(function() {
$('.form-horizontal').submit(function() {
console.log(JSON.stringify($(this)));
var formData = new FormData($(this)[0]);
$.post($(this).attr("action"), formData, function(data) {
alert(data);
});
return false;
});
});
</script>
<form class="form-horizontal" action="/admin" method="post">
<input id="query" type="file">
<input id="query2" type="file">
<button type="submit">Update Data</button>
</form>
Now, in my console I see log that looks like below
In admin method. Request method: GET
In admin method. Request method: POST
**In search method. With request method: GET**
The bolded line is what makes me uncomfortable and looks suspicious to me. When I submit post request to my /admin, why is another GET request executed by flask app ?
#app.route("/<query>", methods=['GET'])
this route is very wide and it grabs all /admin requests. Try to make for example routes /admin/ and /r/
Instead of use:
<form class="form-horizontal" action="/admin" method="post">
You can try this one:
<form class="form-horizontal" action="{{ url_for('admin') }}" method="post">