How to upload file in python webapp2? - python

I am using python webapp2 (Python framework) and google app engine for my project, i want to upload files to my project directory just like move_upload_files in php
Thanks

You can upload files to the blobstore using webapp2. You first must create the upload url when dispatching to your upload form:
self.render('upload-ui.html', {
...
'form_url': blobstore.create_upload_url('/upload_form'),
})
Then in your upload form you use the form_url
<form method="post" action="{{ form_url }}" name="formular" class="ui form" accept-charset="UTF-8"
enctype="multipart/form-data">
The uploaded files are available from self.get_uploads in the post method of your code:
for upload in self.get_uploads():
try:
content_type = blobstore.blobstore.BlobInfo(upload.key()).content_type
if 'video' in content_type:
vid = Video(reference=user)
vid.content = upload.key()
vid.title = blobstore.blobstore.BlobInfo(upload.key()).filename
vid.size = blobstore.blobstore.BlobInfo(upload.key()).size
vid.put()
except Exception, e:
logging.error('There was an exception:%s' % str(e.message))
pass

Related

What is the best way to build a Document Management System in python using GCS or AWS S3?

I'm building a tool where users in a particular account/tenant can upload images/videos (CREATE/DELETE) and also create/delete folders to organize those images. These images/videos can later be dragged and dropped onto a page. This page will be accessible to everyone in that account. So I have thought of 2 architecture flows but both seem to have trade-offs.
I thought I can generate signed url for each of the resource available in the document management system and for each resource that is used in the page. This method works if there are less number of images used in a page. What if the user has 30-40 images in a page, the client has to request signed URLs for each of those resource everytime a user loads the page. This increases latency while rendering the page on the client side.
Another architecture is to put all of the uploaded resource in a public bucket (explicitly stating the user that all uploaded resource will be public). The obvious tradeoff is security.
Is there a way where I can securely allow users to have numerous resources? Something like instead of generating a signedURL for the blob itself, would it be possible to generate a signedURL for a path? Example: instead of generating a signed url for /folder1/folder2/blob.png would I be able to generate a signedURL for /folder1/folder2 so that the client can request for all the blobs within the folder2 without multiple requests to the server?
What I want to achieve is minimal latency without compromising security.
For Google Cloud Storage you can use python and then use Flask as your web framework and then use this code to upload documents:
Your index should look like this
<!doctype html>
<html>
<head>
<title>File Upload</title>
</head>
<body>
<h1>File Upload</h1>
<form method="POST" action="" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
Then your python code would look like this for uploading documents:
from google.cloud import ndb, storage
from google.cloud.storage import Blob
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/', methods=['POST'])
def upload_file():
uploaded_file = request.files['file']
if uploaded_file.filename != '':
uploaded_file = request.files['file']
filename = “someUniiqueFileName”
client = storage.Client(project=“yourProjectName”)
bucket = client.get_bucket("yourProjectName.appspot.com")
blob = Blob(filename, bucket)
blob.upload_from_file(uploaded_file)
return redirect(url_for('index'))
Then to download files you need later you'd add this code where you want to download it from.
bucket_name = "yourProjectName.appspot.com"
 
source_blob_name = "someUniiqueFileName"
 
destination_file_name = "local/path/to/file"
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)

blob = bucket.blob(source_blob_name)
blob.download_to_filename(destination_file_name)
If you have any more questions about this just let me know.

How to fix 405 Method Not Allowed in forms, using Blueprint in Flask

I have a file upload form in HTML, which should be used to upload and save to a static folder. The problem is that it works fine in a simple Flask app, but it just doesn't work using Blueprint templates.
I have tried several different ways of making this work. When I use "url_for", the page doesn't even load (werkzeug.routing.BuildError: Could not build url for endpoint 'upload'. Did you mean 'forms_blueprint.upload' instead?).
But when I change "url_for" to "form_upload.html", the result is always that the method is not allowed.
All thoughts are appreciated.
routes.py:
UPLOAD_FOLDER = '/home/juliosouto/flask-gentelella/app/uploaded_files/'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#blueprint.route('/<template>', methods = ['GET', 'POST'])
#login_required
def route_template(template):
return render_template('form_upload' + '.html')
#blueprint.route('/upload', methods=['POST','GET'])
def upload():
file = request.files['file']
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
form_upload.html:
<form action ="{{ url_for('upload') }}" class= "dropzone" name="file" method = "POST" enctype = "multipart/form-data"></form>
I need the file to be saved to a static folder.
When I use "url_for", the page doesn't even load (werkzeug.routing.BuildError: Could not build url for endpoint 'upload'. Did you mean 'forms_blueprint.upload' instead?).
This means exactly what it says. when you build the URL you need to do it as follows:
{{ url_for('forms_blueprint.upload') }}
Also, as #gittert correctly states, your upload route returns nothing.
This should render a template, or return a redirect to someplace else.

Google app engine with python

I'm new to Google app engine with python ,please help me!
Here is my html code:
<form action="" method="POST">
<div class="form-group">
<label for="uploaded_file">Attached file:</label>
<input type="file" id="uploaded_file" name="uploaded_file">
</div>
<div class="form-group">
<button class="btn-primary" type="submit">Save note</button>
</div>
</form>
Here is my python code:
def post(self):
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file, 'filename', None)
file_content = getattr(uploaded_file, 'file', None)
if uploaded_file:
self.response.out.write(uploaded_file)
self.response.out.write(file_name)
self.response.out.write(file_content)
I deploy my project to Google app engine and visit the website. I choose a picture and click the submit button, it can show uploaded_file(file's name). But, file_name and file_content show None.
If I modify my code :
def post(self):
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file, 'filename')
file_content = getattr(uploaded_file, 'file')
It will show:
File "C:\Users\pc2\Desktop\test\main.py", line 98, in post
file_name = getattr(uploaded_file, 'filename')
AttributeError: 'unicode' object has no attribute 'filename'
Someone help me to get file or picture ,please!
In your form, you need to an 'enctype' attribute so that uploaded files are handled properly - see this answer for more details on enctype. Your form tag should look like this:
<form action="" method="POST" enctype="multipart/form-data">
Change your post method to this:
def post(self):
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file, 'filename', None)
file_content = getattr(uploaded_file, 'file', None)
if uploaded_file is not None:
self.response.out.write(uploaded_file)
self.response.out.write(file_name)
self.response.out.write(file_content)
The change here is changing if uploaded_file: to if uploaded_file is not None:. This is because a successfully uploaded file will not be None, but would still fail your original if test. I would leave the 'None' arguments to getattr in place - these will prevent exceptions if the user clicks on submit but has not uploaded a file.
Finally, uploaded files do not have a file_content attribute, so this will always be None. If you want to access the file's raw bytes you will need to do
file_content = uploaded_file.file.read()
Note that the file content could be very large, and will not render as an image if you just write it out to the response - you'll just see the raw bytes.

How to upload a file in GAE Python NDB through AJAX call without html form submission

I want to upload image files using blobstore API using AJAX POST and not as html form submission. Based on Google search, i figured out that this could be done by uploading the image file to Google Cloud Storage using blobstore API. I went through this link but I am not able to understand it.
I have an html input element of type "file":
Pic <input type="file" name="pic" id="pic_file">
Name <input type="text" name="name" id="name">
Email <input type="text" name="email" id="email">
I have an AJAX call to send other input field values to my python backend:
var user_data = "&name="+$("#name").val() + "&email="+$("#email").val();
$.post("/admin", user_data, after_edit);
In my python file,
class Admin(BaseRequestHandler):
def get(self):
::
template_values = { 'url': url, }
self.generate('adminpage_1.html', template_values);
def post(self):
name = self.request.get('name')
email = self.request.get('email')
app = webapp2.WSGIApplication([
('/', MainHandler),
('/admin', Admin),
], debug=True)
I want to avoid using additional plugins for this if there is a way out without them

uploading files with urllib to a FileField model in Django

I have a django file model that has a models.FileField field and a form that is used to upload files to the server:
class UploadFile(model.Model):
filename = models.FileField(upload_to='uploads')
description = models.CharField(max_length=38, blank=True)
class UploadFileForm(ModelForm):
class Meta:
model = UploadFile
fields = ('filename', 'description')
This is how the view function looks like:
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
new_file = form.save()
Now I would like to have a python script that uses only the standard library to upload files to the UploadFile model using the view function above. However this code does not work because the POST request does not have a FILES method.
import urllib, urllib2
data = urllib.urlencode({'filename': open(uploadfile, "rb"),
'description': 'upload test'})
post_req = urllib2.Request(upload_file_url, data)
result = urllib2.urlopen(post_req)
How could I add a FILES method to the POST request to upload files using a python script? I have also tried to write a different view function that does not used the form but it is not working either.
To see whether your django view works, you could test it using a browser:
<FORM action="{{ upload_file_url }}"
enctype="multipart/form-data"
method="POST">
Description: <INPUT type="text" name="description" value="upload test"><BR>
File to upload: <INPUT type="file" name="filename"><BR>
<INPUT type="submit" value="Send">
</FORM>
It is complicated to replicate it programmatically using only stdlib.
To upload files as multipart/form-data you could use requests library:
import requests
response = requests.post(upload_file_url,
files={'filename': open(uploadfile,'rb'),
'description': 'upload test'})
print response.content
Or urllib2 and poster libraries:
import urllib2
import poster.encode
import poster.streaminghttp
opener = poster.streaminghttp.register_openers()
params = {'filename': open(uploadfile,'rb'), 'description': 'upload test'}
datagen, headers = poster.encode.multipart_encode(params)
response = opener.open(urllib2.Request(upload_file_url, datagen, headers))
print response.read()
It ain't that easy, is not that request doesn't have a FILES method (which is not a method, is a dictionary). The problem is that Django doesn't recognizes files if the request doesn't have the Content-Type:multipart/form-data.
Note that FILES will only contain data if the request method was POST and the that posted to the request had enctype="multipart/form-data". Otherwise, FILES will be a blank dictionary-like object.
Here you can see how a request like that looks like: What should a Multipart HTTP request with multiple files look like?
https://docs.djangoproject.com/en/dev/ref/request-response/
So basically what you'll have to do is add that field to the request you're building and send it to django later.
You can take a look at this pages from django's doc to get more info about that and it will be great if you can sniff or see how the request is before sending it to django so you can know what is missing.
https://docs.djangoproject.com/en/dev/ref/forms/api/
Since there's not a easy/direct answer to this, I hope this can put you in the right direction.
Good luck!

Categories

Resources