Django 1.1.1 chokes on multipart/form-data - python

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.

Related

How to replace standard input () with flask form in Python

My question is similar to Replacing input() portions of a Python program in a GUI. But I need a web UI not desktop UI(tkinter based solution as answered in the link)
You will have to create a webpage with HTML/CSS and create a form in it to get the input. Then, you will have to link the webpage with your backend (flask) to receive the input in python and manipulate as needed. Following a tutorial like this one will help you get started. Or, you can simply search the web for "Form handling in Flask" to find something that suits your needs.
Say you're asking for the user to input their username. You'd do something like this.
HTML
<body>
<form action="" method="post">
<input type="text" placeholder="" value="{{ request.form.username }}">
<input type="submit" value="Submit">
</form>
</body>
Whatever you want to call your variable, you put after request.form
In your program (where you import flask), also import request from flask like so:
from flask import request
Under your route's function, check if the request's method is POST and assign your form variable:
def index():
if request.method == "POST":
foo = request.form["username"]
return render_template("index.html")
So when the user clicks the submit button, foo will be whatever they put in the text box.
You can see more at https://flask.palletsprojects.com/en/1.1.x/quickstart/#accessing-request-data

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?

Pyramid self.request.POST is empty - no post data available

I'm currently working on a pyramid project, however I can't seem to submit POST data to the app from a form.
I've created a basic form such as:
<form method="post" role="form" action="/account/register">
<div class="form-group">
<label for="email">Email address:</label>
<input type="email" class="form-control" id="email" placeholder="you#domain.com">
<p class="help-block">Your email address will be used as your username</p>
</div>
<!-- Other items removed -->
</form>
and I have the following route config defined:
# projects __init__.py file
config.add_route('account', '/account/{action}', request_method='GET')
config.add_route('account_post', '/account/{action}', request_method='POST')
# inside my views file
#view_config(route_name='account', match_param="action=register", request_method='GET', renderer='templates/account/register.jinja2')
def register(self):
return {'project': 'Register'}
#view_config(route_name='account_post', match_param="action=register", request_method='POST', renderer='templates/account/register.jinja2')
def register_POST(self):
return {'project': 'Register_POST'}
Now, using the debugger in PyCharm as well as the debug button in pyramid, I've confirmed that the initial GET request to view the form is being processed by the register method, and when I hit the submit button the POST request is processed by the *register_POST* method.
However, my problem is that debugging from within the *register_POST* method, the self.request.POST dict is empty. Also, when I check the debug button on the page, the POST request is registered in the list, but the POST data is empty.
Am I missing something, or is there some other way of access POST data?
Cheers,
Justin
I've managed to get it working. Silly me, coming from an ASP.NET background forgot the basics of POST form submissions, and that's each form field needs a name== attribute. As soon as I put them in, everything started working.
That does nothing, I belive.
return {'project': 'Register_POST'}
POST parameters are stored inside request, so you have to do something like this.
def register_POST(self, request):
return {'project': request.POST}
To access email input (which has to be named, for example: name="email"), use get() method:
request.POST.get('email')
<form method="post" role="form" action="/account/register"> {% csrf_token %}
Try using "csrf token". hope it works. remaining code looks fine.

Google AppEngine, Django and request.FILES

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.

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