cannot get flask to upload a file [duplicate] - flask

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>

Related

Flask WTForms: Why is my POST request to upload a file not sending the file data?

I am trying to make a form to upload a file, but the file data is not being sent with the request. I'm manually navigating to my file and hitting submit. My FileRequired validator fails. (And if I don't include it the data field on form.scan_file is empty.)
Here's my form:
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired
class ScanForm(FlaskForm):
scan_file = FileField(validators=[FileAllowed(['nii', 'nii.gz', 'zip']), FileRequired()])
Here's my views.py:
from flask import Blueprint, render_template, request, flash, redirect, url_for, session
from .models import Scan
from .forms import ScanForm
from .service import ScanService
from cookiecutter_mbam.utils import flash_errors
blueprint = Blueprint('scan', __name__, url_prefix='/scans', static_folder='../static')
#blueprint.route('/add', methods=['GET', 'POST'])
def add():
"""Add a scan."""
form = ScanForm(request.form)
if form.validate_on_submit():
f = form.scan_file.data
service = ScanService()
xnat_uri = service.upload(session['user_id'], session['curr_experiment'], f)
Scan.create(xnat_uri=xnat_uri)
flash('You successfully added a new scan.', 'success')
return redirect(url_for('experiment.experiments'))
else:
flash_errors(form)
return render_template('scans/upload.html',scan_form=form)
Here's my upload.html:
{% extends "layout.html" %}
{% block content %}
<form method="POST" action="{{ url_for('scan.add') }}" enctype="multipart/form-data">
{{ scan_form.csrf_token }}
<input type="file" name="file">
<input class="btn btn-primary" type="submit" value="Submit">
</form>
{% endblock %}
It doesn't look like I'm making the same mistake as this person. What am I doing wrong?
EDIT: Since posting, I have found this question, but on working through the offered solutions, none seem relevant to my situation.
EDIT 2: At one point, I printed request.files in the Werkzeug debugger and it was an empty dict. I can't reconstruct exactly what I did to get that result. Since then, I've inserted some print statements and in fact, request.files has my file object. So I have a way to retrieve my file. But I am supposed to be able to retrieve my file object at form.scan_file.data (see here). Right now this evaluates to None. More specifically, form.scan_file.has_file() evaluates to False. form.data evaluates to {'scan_file': None, 'csrf_token': <long-random-string> }
Even if I have another way of retrieving my file object, a consequence of this problem is that validation isn't working. My form doesn't pass the FileRequired() validation.
EDIT 3: With my new understanding of my problem, I see that it's similar to this question. However, it's at least apparently not duplicative because none of form = ScanForm(request.form), form = ScanForm(), or form = ScanForm(CombinedMultiDict((request.files, request.form))) make any difference to the behavior outlined in Edit 2.
First of all, check if your data gets posted on that route. Second, I think you don't need to pass request.form to ScanForm, you just need to instantiate it like:
def add():
"""Add a scan."""
form = ScanForm()
...
To check what gets posted with form, instead of
if form.validate_on_submit():
you can use, and print form.scan_file.data:
if form.is_submitted():
print(form.scan_file.data)
Lastly, you can render input file with
{{scan_form.scan_file }} or <input type="file" name="scan_file">
(name attribute of input element should be equal to "scan_file")
Here is my example:
Form:
class ArticleForm(FlaskForm):
article_image = FileField('Article_image', validators=[FileRequired()])
Form in template:
<form action="" method="post" enctype="multipart/form-data">
{{ article_form.csrf_token }}
{{ article_form.article_image }}
<input type="submit" value="submit"/>
</form>
Controller (saving file):
article_form = ArticleForm()
if article_form.validate_on_submit():
f = article_form.article_image.data
name = current_user.username + "__" + f.filename
name = secure_filename(name)
f.save(os.path.join("./static/article_images/", name))
I was stupid enough to forget to add enctype="multipart/form-data" to the form tag which caused the form.file.data to contain only the name of the file and not the whole life.

Implement Facebook Log In with Django

Hi I would really appreciate if somebody could please paste there code here for there Facebook login created for their Django project, whether it is a separate app or not, with a couple of explanations. Pulling User Name, Email and profile pic. Thank you
It took me a week but I have implemented Facebook login the hard way. If you don't want a 3rd party app on your site (more secure and trustworthy for users) here are the steps:
Get the FB login button here: (https://developers.facebook.com/docs/facebook-login/web/login-button). You can change the settings of the button before you copy the code.
Get the javascript plugin here (https://developers.facebook.com/docs/facebook-login/web). I suggest copying the example and modifying the following:
Javascript:
if (response.status === 'connected') {
// Logged into your app and Facebook.
FB.api('/me', {fields: 'name, email'}, function(response) {
console.log('Successful login for: ' + response.name);
document.getElementById("your_name2").value = response.name;
document.getElementById("your_email").value = response.email;
document.getElementById("myForm").submit();
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + response.email + '!';});
Once logged in and 'connected' you need to change the info you call. Add the {fields...} you require above. Keep the log to see if it's working.
Submit the info pulled in 2 into a hidden form in order to send it to a view and model. Here is the form (hellls just default value):
Form template:
<form action="{% url 'facebooklogin:register' %}" method="post" style="display: none;" id="myForm">
{% csrf_token %}
<label for="your_name">Your name: </label>
<input id="your_name2" type="text" name="your_name" value="helllllls">
<input id="your_email" type="text" name="your_email" value="helllllls">
<input type="submit" value="OK">
</form>
Set up your form, model and view to handle the information as you want. Get profile pic but simply adding an ImageField to form.
URL:
url(r'^registerfb/$', views.get_name, name='register')
VIEW:
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
logger.error('Form is valid and running')
logger.error(request.POST.get('your_name'))
logger.error(request.POST.get('your_email'))
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'facebooklogin/name.html', {'form': form})
FORM:
class NameForm(ModelForm):
class Meta:
model = FBUser
fields = ['your_name', 'your_email',]

Scrapy FormRequest How to check if URL is needed

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.

Search field in Django Template

Search field in Django Template
How to create search field in Django Template similar to this image
http://asciicasts.com/system/photos/1204/original/E354I01.png
I try this in github
https://github.com/rg3915/vendas/commit/e0c67fd8154a3b8e450ec3db38705cdd7efc1350
But i do not know how to finish.
You're talking about search field but essentially is just a form, you have an input (the search box) and you receive that input in your view.
Little example to manage forms and GET actions:
views.py:
def your_view(request):
''' This could be your actual view or a new one '''
# Your code
if request.method == 'GET': # If the form is submitted
search_query = request.GET.get('search_box', None)
# Do whatever you need with the word the user looked for
# Your code
template
In your template, the most important thing for this is the form, you should have something like this:
# Your template code
<form type="get" action="." style="margin: 0">
<input id="search_box" type="text" name="search_box" placeholder="Search..." >
<button id="search_submit" type="submit" >Submit</button>
</form>
# Your template code
action='.' <-- This tells django to do the GET action in the same URL as you are
action='/other/url/' <-- This tells django to do the GET in that URL
This form is just an HTML form, you can use also Django Forms
urls.py
Your URL file has to be the same you had before. You don't need to do any change to your actual URL, it should be something like:
url(r'^your_url/?$', 'yourproject.views.your_view', name='your_url_name'),
Anyway I recommend you to check some information like:
Django: Working with forms
Django Forms
Django Tutorial forms
Frontend: Template
create a form with a search box(using html ,css)
<form type="get" action="exact_url" >
<input id="search_box" type="text" name="search_box" placeholder="Search..." >
<button id="search_submit" type="submit" >Submit</button>
</form>
Backend: View
write a funtion in views.py
Search | Django documentation | Django (https://docs.djangoproject.com/en/3.1/topics/db/search/#search) use it writing query
the jsonresponse can be rendered using template language Templates | Django documentation | Django (https://docs.djangoproject.com/en/3.1/topics/templates/#the-django-template-language)
write a query using __contains
def your_view(request):
if request.method == GET:
search_text = request.GET.get(search_box", None)
records=Table.objects.filter(columnn__contains=search_text)
from django.http import JsonResponse
return JsonResponse({"result_records":records})
your url should be same as in **form(template) **and your_view should be same as in views.py (View)
url(r'^exact_url/?$', 'yourproject.views.your_view')

My csv export download button is broken

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)