Google AppEngine, Django and request.FILES - python

Situation: An html form (with the method="POST" and enctype="multipart/form-data" attributes set properly) is submitted to the server, which is Django on Google's AppEngine. It contains a file input, which is moved (not cloned) into said form and submitted through an iframe. For small files (~1mb or less) the submitted files are being found in the request.FILES dictionary, and stored in a blob. For files above 1mb, however, the look into request.FILES is returning an error, claiming the key (which is the name of the file input element) is not found in the given dict, and in fact that the request.FILES (and request.POST) dicts are empty.
Question: Is this due to a AppEngine limitation (if so, is there a workaround?) Is this related to Django in some way (do note that the enctype and method are set appropriately)? Is there some other element that is missing?
Additional Information: Please also note that I am a javascript programmer filling in for an absent Python programmer, and know only the basics. Please tailor your answers accordingly.
Relevant Python:
def media_image_upload(request):
if request.method == 'POST':
img = request.FILES['img']
Relevant html:
<form id="hiddenUpForm" style="display:none;" action="http://localhost:8080/media/imageUpload" enctype="multipart/form-data" target="upTarget" method="POST">
<input name="img" id="img" type="file" accept="image/*">
<iframe id="upTarget" name="upTarget" src="" style="width:0;height:0;border:0px solid #fff;"></iframe>
</form>

I believe that in order to upload files that are larger than 1 MB, you need to use the Blobstore API to create a special URL that is used for the upload; it can't be your regular <1 MB URL.
The controller code that generates the HTML page that contains the upload form would use upload_url = blobstore.create_upload_url('media/imageUploadBig') and would then add upload_url to your template values and render the template.
The template, in turn, would contain a FORM definition something like this:
<form id="hiddenUpForm" style="display:none;" action="{{ upload_url|safe }}" enctype="multipart/form-data" target="upTarget" method="POST">
This means that you either need to have two different forms -- one for files that are less than 1 MB and one for files that are larger -- or you can store all of your images in the Blobstore.
See the Blobstore docs for more information.

Related

Flask routing does not give desired results, URL not getting appended for some instance

I am building a web-app using flask where I am trying to route some URLs
I have three routes with me
a) "/"
b) "/teacher"
c) "/student"
The routing works fine for "/" and"/student" The URL gets appended after clicking the submit button for student and"/student" gets appended in URL but on clicking the button associated with "/teacher" the URL doesn't gets appended and "/" page keeps on loading up.
Please help me out here and tell me what wrong I am doing
My Python code:
#app.route('/', methods=['GET', 'POST'])
def select():
return render_template("select.html")
#app.route('/teacher', methods=['GET', 'POST'])
def index():
return render_template("index_teacher.html", title="Faculty login")
#app.route('/student', methods=['GET', 'POST'])
def index1():
return render_template("index_student.html", title="Student login")
Part of my html code from select.html:
<form action="/teacher" method = "post">
<input type="submit" class="submit" value="Login as Teacher">
</form>
<br>
<form action="/student" method="post">
<input type="submit" class ="submit" value="Login as Student">
</form>
One more thing about the code, when I add a text box above the first submit button, both the button starts working and give desired results.
Thanks in advance!
I think you have just a little typo in the html. The input tag of teacher didn't close >.
<form action="/teacher" method = "post">
<input type="submit" class="submit" value="Login as Teacher">
</form>
<br>
<form action="/student" method="post">
<input type="submit" class ="submit" value="Login as Student">
</form>
EDIT:
In the case that the question was copied incorrectly, I don't know what should be wrong with your code. For me your sample code works just fine. So from my experience with flask and html forms the most common errors I made are the following, maybe it's one of them (the list may serve other too, so I will also add points that do not make sense for your case):
method name of two routes collide (e.g. both '/' and '/teacher' are assigned to function index, but that should give an error when starting the server, so not really possible)
an html tag is not closed properly, so the form in question is not parsed as a valid form (that was my guess with above answer, also makes sense with the text box, which may close the corrupt tag => in html an open tag is closed by the first following closing tag)
typo in the form action attribute (check the network tab in your browsers developer tools, maybe you get an error response to something like "taecher", which results in a redirect to "/", again not really plausible with the fact that it suddenly works when you add the text box)
typo in the route or the returned template (again not plausible with explained behavior with the added text box)
That's all I can think of at the moment. I hope it helps with the search. if you could add more of your html code, maybe I find something suspicious.

Upload jpg with flask and html

I'm a beginner and i'm making a blog with flask and html right now but it only can post title and content, but i want to post some picture init, so if anyone know whats the essayist way to post it (print the pic on flask app) and can storage in db file, can u please help me out? Because i'm stuck in this for so long.
If you are using a flask form to upload a file, then from flask_wtf.file import FileField can be used as the form field to upload files.
class UploadImageForm(Form):
file = FileField(label='File Upload')
submit = SubmitField('Submit')
On the HTML side you will want:
<form action="{{ url_for(your.route, **kwargs) }}" method="POST" enctype = "multipart/form-data">
{{ form.name_of_file_field }}
{{ form.submit }} <!-- Or an input tag -->
</form>
Then your route that will be called when the form is submitted must require a POST method. In development, you can store your files locally within the static folder, but I would advise to store them in remote storage before putting the app on a server.
Once the file is stored and uploaded, then in your html you can render the image with:
<img class="image" src="{{ url_for('static', filename=image_file_path) }}"> where image_file_path is the path to the image. This path should be stored as an environment variable. The image file name can be stored on your db within one of your models data columns as a string. I suggest creating UUID's as the image file name so you are not dependent on the user's upload (i.e. if the filename is in a different language).
Miguel Grinberg has a great tutorial on this that will cover all of this and more including working with image objects, image validation, and security: https://blog.miguelgrinberg.com/post/handling-file-uploads-with-flask

Pyramid: using form data for route matching and POST simultaneously

I'm using Pyramid to build a webapp, and I've got two views where one leads to the other:
config.add_route("new", "/workflow/new")
config.add_route("next", "/workflow/{id}/next")
The new view is really very simple and presents only an HTML form as a Jinja2 template for the user to fill in some information:
<form method="post" action="{{ request.route_url('next',id='') }}" >
<input type="text" name="id" value="Identifier" />
...
<input type="submit" name="next" value="Next" />
</form>
The question here regards the action of that form: how can I use the content of the text input field id, perhaps process it a little, and then pass it on in the route request?
Note that in this scenario the form data is passed from the new view to the next view, and that should stay the same.
When the form is posted, the forms fields will be available in the request object, see
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/webob.html#request
I believe it is also a good idea to post to the same url (<form action="#" method="post">), so that you can validate the form. Then you can process and redirect to the next url when the form is valid, or recreate the form with errors if it isn't.
So your view may end up something like this;
from pyramid.httpexceptions import HTTPFound
from pyramid.url import route_url
def myview(request):
if request.method == 'POST':
# Validate the form data
if <form validates successfully>:
# Do any processing and saving here.
return HTTPFound(location = route_url('next', id=request.params['id'], request=self.request))
else:
request.session.flash("The form isn't valid.")
# Do some stuff here to re-populate your form with the request.params
return { # globals for rendering your form }
There are already many questions/answers addressing this, such as How can I redirect after POST in Pyramid?

Django 1.1.1 chokes on multipart/form-data

Initial story
I'm trying to implement file upload using a simple form (I'm pasting stripped version, but all important parts are included):
<form method="POST" action="" enctype="multipart/form-data">
<input type="file" name="up_file" size="50">
<input type="hidden" name="cpk" value="{{c.pk}}">
<input type="submit" name="btn_submit">
</form>
Now, server-side script running under wsgi was receiving strange values for "cpk" field and request.FILES was empty empty request.FILES and request.POST dictionaries, so I decided to switch to development server for debugging.
Surprisingly, ipdb debugger hangs after typing both request.POST and request.FILES and pressing enter... On the other hand, when I remove enctype="multipart/form-data" from tag, I'm able to check both request.POST and request.FILES, but of course request.FILES is empty then.
(Also wsgi version seems to be healed by removal of enctype="multipart/form-data"...)
Update
I tried all combinations of Opera 10//Firefox 3.5, enctype="multipart/form-data"//no multipart/form-data and dev server//mod_wsgi. The result is that it's enctype="multipart/form-data" that breaks the show. So now I'm going to check Django bugtracker if it's a known issue.
Meantime, maybe someone here can point me in the right direction
You may need to provide your view and form code as we use form uploads with enctype="multipart/form-data" in Django 1.1.1 with great success.
The following dummy app, for example, works perfectly in the dev server.
views.py
from django import forms
from django.shortcuts import render_to_response
class UploadForm(forms.Form):
cpk = forms.CharField(max_length=256)
f = forms.FileField()
def my_upload_view(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
print "Got cpk",form.cleaned_data['cpk']
print "Got file",request.FILES['f'].read()
else:
form = UploadForm()
return render_to_response('upload.html', {'form':form})
upload.html
<html>
<body>
<form enctype="multipart/form-data" method="post">
{{ form.f }}
{{ form.cpk }}
<input type="submit" />
</form>
</body>
</html>
I'm using the django form instance to render the file input, but it renders the very common <input type="file" name="f" id="id_f" />.
Using this sample, I get the content of the file (I've tested using a simple text file) printed to the terminal from my dev server. The few gotchas and tests I can recommend are:
ensure that the file you are uploading is less than settings.FILE_UPLOAD_MAX_MEMORY_SIZE (the default is 2.5 MB)
double-check that you haven't defined any custom file upload handlers that may be breaking the upload process (settings.FILE_UPLOAD_HANDLERS)
try uploading a very simple file (like a small text file) to see if the issue still persists with something basic
use a tool to inspect the raw HTTP request/response traffic (firebug will do this for you, and there are some stand-alone apps that will act as a proxy to help you here too)... sometimes the solution will jump out when you can see the raw traffic.
In case you haven't found them yet, the django file upload docs have a fair number of examples.

How to upload a file with django (python) and s3?

I'm looking for a way to upload a file to s3. I am using django. I am currently using amazon's python library for uploading along with the following code:
View:
def submitpicture(request):
fuser = request.session["login"]
copied_data = request.POST.copy()
copied_data.update(request.FILES)
content_type = copied_data['file'].get('content-type')
ffile = copied_data['file']['content']
key = '%s-%s' % (fuser, ''.join(copied_data['file']['filename'].split(' ')))
site_s3.save_s3_data(key, ffile, content_type)
Template:
<form action="/submitpicture/" method="POST">
<input type="file" id="file" name="file" />
<input type="submit" value="submit" />
</form>
However, when I actually try to run it i get the following error:
"Key 'file' not found in <QueryDict: {}>"
#MultiValueDictKeyError
I really don't see what I'm doing wrong. Can someone point me in the right direction?
Edit: Just in case someone wonders, I am planning on adding some validation after I get the actual upload working.
You will have to provide the enctype attribute to the FORM element (I've been bitten by this before). For example, your FORM tag should look like:
<form action="/submitpicture/" method="POST" enctype="multipart/form-data" >
Without the enctype, you will find yourself with an empty request.FILES.
Instead of doing this manually I would take a look at the storage backend David Larlet has written for Django, django-storages
Adding enctype="multipart/form-data" seems like something that's worth mentioning in the "File Uploads" section of the django docs (http://docs.djangoproject.com/en/dev/topics/http/file-uploads/). Thoughts?

Categories

Resources