Python/Django - using a view method on an upload file - python

I have this view:
def index(request):
file = open("SK ✌😜✌.txt", encoding="UTF-8")
data = file.read()
file.close()
lines = data.split("\n")
...More code...
In this view i open a file from the very first moment the app starts and i do some work on the file, is a story, and when i start the server and go to http://127.0.0.1:8000/(Name Of The App), i see all the work that i have done on that file.
What i want to do is to do that same work, starting with the reading of the file, BUT i want to do that with the file that the user uploads in that moment. I have this that i took from bootstrap:
<div class="form-group">
<label for="exampleInputFile">File input</label>
<input type="file" id="exampleInputFile">
</div>
I guess i have to use in some way the id of the input but i`m not really sure how to pass this file that the user uploads in the ui to the method that i have in my views.py
Any help will be really appreciated

You need to have a name attribute in your <input> template code.
<input type="file" id="exampleInputFile" name="some_file">
Then to access the file in your view, you need to use request.FILES attribute.
As per the Django docs on HttpRequest.FILES attribute:
A dictionary-like object containing all uploaded files. Each key in
FILES is the name from the <input type="file" name="" />. Each
value in FILES is an UploadedFile.
Your code should be something like:
def index(request):
if request.method=="POST":
uploaded_file = request.FILES['some_file'] # get the uploaded file
# do something with the file
Note: request.FILES will only contain data if the request method was POST and the <form> that posted to the request had enctype="multipart/form-data. Otherwise, FILES will be a blank dictionary-like object.

Related

How to pass flask HTML form data into separate .py script, then display back on the same HTML page

Very new to python/flask and actually to programming in general.
I'm trying to create a flask html form that will pull data from an API and take the user input and run it through a separate python script file named cityid.py. Then have it return the results of the cityid.py script back into the same HTML page, but below the input box.
End result would be something like this on the HTML page:
Enter your city: ______________
(submit button)
results printed here from the cityid.py script
Here's the form I have in my HTML file.
<form name="search" action="/cityid.py" method="POST">
<input type="text" name="city_input">
<input type="submit1" name="submit" value="submit">
</form>
within my cityid.py script I have the following to start off the script, referred to this question. Posting html form values to python script
import cgi
def city_details():
form = cgi.FieldStorage()
city = form.getvalue('city_input')
#rest of the script below, but the city variable is what I need to be user input from the flask form
Here's what I have in the main.py file
#app.route("/city_details2", methods=['GET','POST'])
def city_details2():
if request.method == "POST":
return render_template("city_details2.html", city_details=city_details())
Now I can't seem to even start the flask web server because I get the following error:
TypeError: can only concatenate str (not "NoneType") to str
It's basically already trying to run the separate cityid.py script without having the user input first to get the city variable.
Anyone have an input on what I'm doing wrong here? I suspect it's something wrong with the #app.route? Or how do I get the user input first before running the cityid.py script?
I believe this is going to help you.
Here is a simple URL, which passes two values to hello_get.py program using GET method. /cgi-bin/hello_get.py?first_name=ZARA&last_name=ALI
Below is hello_get.py script to handle input given by web browser. We are going to use cgi module, which makes it very easy to access passed information
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')
HTML :
<form action = "/cgi-bin/hello_get.py" method = "get">
First Name: <input type = "text" name = "first_name"> <br />
Last Name: <input type = "text" name = "last_name" />
<input type = "submit" value = "Submit" />
</form>

why do I get "FileNotFoundError" when doing fileupload with Django?

I am writing a file upload page with Django/Python. I get this error:
FileNotFoundError: [Errno 2] No such file or directory: '48.png'.
Here is the relevant part of the view, which handles the upload:
`if request.method == 'POST':
form = myform(request.POST, request.FILES)
if form.is_valid():
print("FORM VALID")
f = request.FILES['thefile']
print("f:" + f.name)
print(pref+'/'+str(f))
open(f.name, 'rb')
else:
print('FORM NOT VALID')
Things go wrong in the open(f.name statement. The form is in a template:
<form method="post" action="/dataset_storage_upload/{{ pk }}/{{pid}}/" name="submit" enctype="multipart/form-data">
{% csrf_token %}
{{ theForm.as_p }}
<button type="start_upload" value="Submit" onclick="document.upload.submit() ">Upload</button>
</form>
and this is the form:
class myform(forms.Form):
thefile = forms.FileField()
I have this information in the console
FORM VALID
f:48.png
/17/3/48.png
(/17/3 is the prefix)
In the Traceback, in the browser, under local vars, I have this:
pref '/17/3'
mylist[]
f <InMemoryUploadedFile: 48.png (image/png)>
pk '17'
form <myform bound=True, valid=True, fields=(thefile)>
request<WSGIRequest: POST '/dataset_storage_upload/17/3/'>
I think this tells me that there is a file 48.png in memory. So why is it not there when I open it?
Many thanks for your attention.
It's only there in memory, not on the actual filesystem. Django File objects provide a wrapper around both real files, and in-memory files.
For example, if you were handling a file that was coming from a FileField on some model, what you're doing would work, but the file you're handling doesn't yet exist on the system.
If you want to read the file in your view, you can just call File.read:
f = request.FILES['thefile']
contents = f.read()
By default, if an uploaded file is smaller than 2.5 megabytes, Django
will hold the entire contents of the upload in memory. This means that
saving the file involves only a read from memory and a write to disk
and thus is very fast.
I changed f.open( into f.read( and now it works perfectly. For completeness: My goal is to store the uploaded file in S3, so that now I do
s3.Object('mybucket', str(pk)+'/'+str(p)+'/'+str(f)).put(Body=f.read(),Metadata={'project': '17','dataset':'3','filename':str(f)})
and this works.

Getting file location from an html form

EDIT: Added the solution to my code, as suggested by Martijn Pieters.
I'm writing a web application that should have an image upload feature. Actually it is uploading directly to imgur.com through their api. So far I can upload an image to imgur through the terminal by running my python script. But I want the user to be able to select an image through an html form. All I actually need (I think) is the path for the file, then I have a script that converts the image to base64. As I write this I realize that the script might only work when it's run locally, and not from a browser. I have been googling for two days. I get a lot of results about cgi.FieldStorage() but can't seem to get that to work as I get a KeyError.
This is the file input part of my form:
<div class="container">
<form role="form" class="form-horizontal form-inline" method="post" enctype="multipart/form-data">
<div class="col-md-12">
<div class="form-group">
<label for="image" class="control-label">Product image</label>
<input type="file" id="image" name="imageurl" value=""/>
</div>
</div>
And then I need to be able to handle the input in my python script:
class MainPage(BlogHandler):
def get(self):
self.render("front.html")
def post(self):
image = self.request.POST.get("imageurl")
logging.info(getUrl(image))
This is the code for sending the image to the imgur api:
def getUrl(image):
API_URL = "https://api.imgur.com/3/upload.json"
image_read = image.file.read()
b64 = base64.b64encode(image_read)
data = {
'image': b64,
'type': base64,
'title': 'testupload'
}
response = requests.post(API_URL, data, headers={'Authorization': 'Client-ID my-cient-id'})
url = response.json()['data']['link']
return url
I developing in Google App Engine and using Jinja2 as the templating engine.
I'm a beginner programmer so I hope to get some pointers on my problem. I feel like I'm stuck on searching for the answer. I've read that the browser does not know anything about the file system of the computer for security reasons, but websites exist where you can choose a file from your computer to upload, so I figure it must be possible to achieve. :)
EDIT: Added the solution to my code, as suggested by Martijn Pieters.
Uploading an image requires that you change the form encoding to multipart/form-data:
<form encoding="multipart/form-data" role="form" class="form-horizontal form-inline" method="post">
See application/x-www-form-urlencoded or multipart/form-data?
Because this is a POST request, you'll find the fields in request.POST:
def post(self):
imageurl = self.request.POST.get("imageurl")
logging.info(imageurl)
although request.get() will search both query parameters and POST form data.
A form upload is returned as a cgi.FieldStorage() object; this has a file attribute, which gives you a file-like interface. You could just read the data into memory:
image = self.request.POST.get("imageurl")
image_read = image.file.read()
b64 = base64.b64encode(image_read)

uploading file in django and python?

<input type="file" name="doc-file" multiple/>
file_path = request.FILES.get('doc-file')
My return value of file_path is None
But when I do file_path = request.POST.get('doc-file') it returns filename . What is the best way to upload a file in python and django?
It sounds like you might be forgetting to include enctype="multipart/form-data" in your form tag. See Django's docs on file uploads for details.
Edit: formatting

Upload files in Google App Engine

I am planning to create a web app that allows users to downgrade their visual studio project files. However, It seems Google App Engine accepts files uploading and flat file storing on the Google Server through db.TextProperty and db.BlobProperty.
I'll be glad anyone can provide code sample (both the client and the server side) on how this can be done.
In fact, this question is answered in the App Egnine documentation. See an example on Uploading User Images.
HTML code, inside <form></form>:
<input type="file" name="img"/>
Python code:
class Guestbook(webapp.RequestHandler):
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get("content")
avatar = self.request.get("img")
greeting.avatar = db.Blob(avatar)
greeting.put()
self.redirect('/')
Here is a complete, working file. I pulled the original from the Google site and modified it to make it slightly more real world.
A few things to notice:
This code uses the BlobStore API
The purpose of this line in the
ServeHandler class is to "fix" the
key so that it gets rid of any name
mangling that may have occurred in
the browser (I didn't observe any in
Chrome)
blob_key = str(urllib.unquote(blob_key))
The "save_as" clause at the end of this is important. It will make sure that the file name does not get mangled when it is sent to your browser. Get rid of it to observe what happens.
self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
Good Luck!
import os
import urllib
from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
class MainHandler(webapp.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit" name="submit" value="Submit"> </form></body></html>""")
for b in blobstore.BlobInfo.all():
self.response.out.write('<li>' + str(b.filename) + '')
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.redirect('/')
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, blob_key):
blob_key = str(urllib.unquote(blob_key))
if not blobstore.get(blob_key):
self.error(404)
else:
self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
def main():
application = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler),
], debug=True)
run_wsgi_app(application)
if __name__ == '__main__':
main()
There is a thread in Google Groups about it:
Uploading Files
With a lot of useful code, that discussion helped me very much in uploading files.
Google has released a service for storing large files. Have a look at blobstore API documentation. If your files are > 1MB, you should use it.
I try it today, It works as following:
my sdk version is 1.3.x
html page:
<form enctype="multipart/form-data" action="/upload" method="post" >
<input type="file" name="myfile" />
<input type="submit" />
</form>
Server Code:
file_contents = self.request.POST.get('myfile').file.read()
If your still having a problem, check you are using enctype in the form tag
No:
<form encoding="multipart/form-data" action="/upload">
Yes:
<form enctype="multipart/form-data" action="/upload">
You can not store files as there is not a traditional file system. You can only store them in their own DataStore (in a field defined as a BlobProperty)
There is an example in the previous link:
class MyModel(db.Model):
blob = db.BlobProperty()
obj = MyModel()
obj.blob = db.Blob( file_contents )
Personally I found the tutorial described here useful when using the Java run time with GAE. For some reason, when I tried to upload a file using
<form action="/testservelet" method="get" enctype="multipart/form-data">
<div>
Myfile:<input type="file" name="file" size="50"/>
</div>
<div>
<input type="submit" value="Upload file">
</div>
</form>
I found that my HttpServlet class for some reason wouldn't accept the form with the 'enctype' attribute. Removing it works, however, this means I can't upload any files.
There's no flat file storing in Google App Engine. Everything has to go in to the Datastore which is a bit like a relational database but not quite.
You could store the files as TextProperty or BlobProperty attributes.
There is a 1MB limit on DataStore entries which may or may not be a problem.
I have observed some strange behavior when uploading files on App Engine. When you submit the following form:
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="img" />
...
</form>
And then you extract the img from the request like this:
img_contents = self.request.get('img')
The img_contents variable is a str() in Google Chrome, but it's unicode in Firefox. And as you now, the db.Blob() constructor takes a string and will throw an error if you pass in a unicode string.
Does anyone know how this can be fixed?
Also, what I find absolutely strange is that when I copy and paste the Guestbook application (with avatars), it works perfectly. I do everything exactly the same way in my code, but it just won't work. I'm very close to pulling my hair out.
There is a way of using flat file system( Atleast in usage perspective)
There is this Google App Engine Virtual FileSystem project. that is implemented with the help of datastore and memcache APIs to emulate an ordinary filesystem. Using this library you can use in you project a similar filesystem access(read and write).

Categories

Resources