When i send the <input type='file' src='D:/.../image.png'>'s src throught Ajax to views.py in the views the src is not correct, It appears like D:/fakepath/imag.png the fakepath is some security thing made by browser But how I can upload the form's content when I can't get the path of the file input?
First of all you need to set your enctyoe to multipart/form-data
In django you'll find your files under request.FILES, the easiest way to submit the form is to pass the data with js formdata object, it basically takes the entire form and adds it to your ajax request so you can handle it in django like a regular form
Related
I added a Django form to my Bootstrap nav bar to be included on every page, and it renders as it should with the appropriate values. The form was added using an inclusion_tag. However, I'm now at a loss as to how to handle the request from the form. Upon submission, whichever page the user was on should reload with updated content from the form submission. For more context, see my earlier question: How to place a django form in a nav bar so that it appears on every page?
Answering my own question (again). To handle a request from a form that appears on every page and loaded via a custom template tag, create a url path and corresponding view -- e.g. '/form-submission/' and form_submission_view. In the view, handle the form processing logic as you normally would for a POST request, but then return a redirection back to whatever page the user was on when the form was submitted, like so:
return redirect(request.POST.get('path'))
I am building a REST API server that handles POST requests. The content type in the request is "application/x-www-form-urlencoded".In the request body, we are sending "data1" (some string) and "image" ( a file)
Here's the sample inputForm code I have:
from django import forms
class RequestForm(forms.Form):
data1= forms.CharField(label='data1',max_length=10000)
image = forms.ImageField()
I then validate the content in the form request:
if request.method == 'POST':
form = RequestForm(request.POST)
print("Form content: {0}".format(form))
if form.is_valid():
print("Works")
else:
print("Issue")
Now, when I send the above mentioned data, I always get an error. It prints "Issue". In addition, the line taht prints form content shows it as an error. Something like:
<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="data1" maxlength="10000"
One interesting point: if I remove "Content-type" from the request header, it works.
Any inputs on how I can read the form data correctly when we use content type as application/x-www-form-urlencoded.
thanks in advance...
As per Django Forms documentation:
By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception
You are on the right track, you should send the form as multipart/form-data as per this thread: Thread about form Content types
Found the solution. To begin with, I am sending a file in the input. So I should use content type as "multipart-formdata".
In addition, I am using Postman to pump in the REST API requests. In the body of the request, I set form-data which automatically sets the headers correctly based on what I am sending in the body. I was trying to override it with my own header which is not right.
When I resent my http POST request with no headers in Postman, it worked. (of course, I did verify the final http request itself and confirmed Postman is setting the header correctly)
So I have a a HTML page with a table in it which contains details of a certain model. Each row contains details of a different object. I have a cell for a button as well.
Now, what I want is for the user to be able to click on the button and it should take them to the appropriate page for that particular user that they've clicked on. The way I can do this now is by creating a URL that takes a user_id argument along with a view to redirect it to a template. This url can then be added to the button. However, I don't want the user_id to be shown in the URL (being shown in Inspect Element is okay (as in the row ID)).
This rushed, so sorry. How can I do this?
Is there a way to do it without putting any information whatsoever in the URL?
Thank you!
One way to do this is to send user ids from a POST instead of a GET for getting the user info, when the user clicks the button, you submit a hidden form which contains user_id (which you will update accordingly) and pass it to Django. On this POST call you will wire a render of the page for the user according to the POST parameter you are expecting containing the user id.
You can read the post parameters on a request via:
request.POST.get('user_id')
The downside of this approach is that you won't be able to share the link for a certain user, because the link will only contain the get parameters.
Maybe you can refactor your application to use some kind of SPA framework on the front-end. In this way you can load any content on your current page and the URL never changes if you don't want. Take a look for example at AngularJS or Durandal. Both works well with Django.
You can also solve the problem by using POST instead of GET but in my opinion that's not a very elegant solution because POST requests should be used just when you send data to the server.
If your worried about security I don't think keeping the user_id secret will be effective but if for some other reason you have to do this put it in session and redirect to user page without any parameters.
Put your table inside a form and store the id in an attribute of the button on each row:
<button class="mybutton" data-id="{{ my_object.id }}">view</button>
Put a hidden field at the bottom of your form:
<input type="hidden" id="user_id" name="user_id" />
Javascript:
$("table .mybutton").click(function(e) {
e.preventDefault();
$("#user_id").val($(this).attr("data-id"));
$("#my_form").submit();
});
In your table view:
if request.method == "POST":
request.session["user_id"] = request.POST.get('user_id')
return redirect("user_page")
In your details view:
user_id = request.session["user_id"]
creating urls
If the url is relevant to the user; then use the user_id; e.g. http://example.com/mysite/users/<user_id>/userstuff.
obfuscation is not security.
obfuscation is not a permission scheme.
Other possibilities:
http://example.com/mysite/users/<uniqueusername>/userstuff.
http://example.com/mysite/users/<slug>/userstuff.
http://example.com/mysite/users/<encoded>/userstuff, where encoded is either 2-way encoding, or a field on the user model that is unique.
getting logged in user (request.user)
If the url has nothing to do with the user, but you need to get the authenticated user then read the docs: https://docs.djangoproject.com/en/1.7/topics/auth/default/#authentication-in-web-requests.
def my_view(request):
if request.user.is_authenticated():
# use request.user
else:
# something else
There are a few tiny related questions buried in here, but they really point to one big, hairy best practice question. This is kind of a tough feature to implement because it's supposed to do a couple tricky things at once...
drag-and-drop multi-file uploader (via Javascript)
multi-page form (page one: upload and associate files with an existing document model;
page two: update and save file/document objects and meta-data to database)
...and I haven't found a pre-existing code sample or implementation anywhere. (Depending on one's approach, it could sweep off the table or automagically answer all the related/embedded/follow-on questions.) Bottom-line, the purpose of this post is to answer this question: What's the most elegant approach which minimizes the intervening questions/problems?
I'm using this implementation of a drag-and-drop JQuery File Uploader in Django to upload files...
https://github.com/miki725/Django-jQuery-File-Uploader-Integration-demo
The solution I link to above saves files on the filesystem, of course, but in batches per upload session, via creating a directory for each batch of files, and then assigning a UUID to each of those directories. Each uniquely named directory on the filesystem contains files uploaded during that particular upload session. That means any sort of database storage method first has to tease apart and iterate over all the files in the filesystem directory created for each upload session by this solution.
Note: the JQuery solution linked to above doesn't use a form (in forms.py) inside the app directory. The form is hardcoded into the template, which is already a bit of a bummer...'cause now I also have to find a nice way to bind each of the above files in each batch to a form.
I think the simplest--albeit perhaps least performant solution--is to create two views, for two forms...to save each file to the database in the view on the first page, and then update the database on the second page. Here's the direction I'm presently rolling in:
IN THE TEMPLATE...
...uploader javascripts in header...
<form action="{% url my_upload_handler %}" method="POST" enctype="multipart/form-data">
<input type="file" name="files[]" multiple
</form>
IN VIEWS.PY...
def my_upload_handler_0r_form_part_one(request):
# POST (in the upload handler; request triggered by an upload action)
if request.method == 'POST':
if not ("f" in request.GET.keys()):
...validators and exception handling...
...response_data, which is a dict...
uid = request.POST[u"uid"]
file = request.FILES[u'files[]']
filename = os.path.join(temp_path, str(uuid.uuid4()) + file.name)
destination = open(filename, "wb+")
for chunk in file.chunks():
destination.write(chunk)
destination.close()
response_data = simplejson.dumps([response_data])
response_type = "application/json"
# return the data to the JQuery uploader plugin...
return HttpResponse(response_data, mimetype=response_type)
# GET (in the same upload handler)
else:
return render_to_response('my_first_page_template.html',
{ <---NO 'form':form HERE
'uid': uuid.uuid4(),
},
context_instance = RequestContext(request))
def form_part_two(request):
#here I need to retrieve and update stuff uploaded on first page
return render_to_response('my_second_page_template.html',
{},
context_instance = RequestContext(request))
This view for the first page leverages the JQuery uploader, which works great for multi-file uploads per session and does what it's supposed to do. However, as hinted above, the view, as an upload handler, is only the first page in what needs to be a two page form. On page two, the end user would subsequently need to retrieve each uploaded file, attach additional data to the files they just uploaded on page one, and re-save to the database.
I've tried to make this work as a two-part form via various solutions, including form wizards and/or generic class based views...following examples mainly enabling data persistence via the session. These solutions get rather thorny very quickly.
In summary, I need to...
upload multiple files in a uniquely identified batch (via drag and drop)
tease apart and iterate over each batch of uploaded files
bind each file in the batch to a form and associate it with an existing document model
submit / save all of these files at once to the database
retrieve each of those files on the following page/template of a potentially new form
update metadata for each file
resubmit / save all of those files at once to the database
So...you can see how all of the above compounds the complexity of a simple file upload, and increases the complexity of providing the feature, by involving related questions like:
forms.py: how best to bind each file to a form
models.py: how to associate each file with a pre-existing document model
views.py how to save each file in accordance with pre-existing document model in Postgres in the first page; update and save each document in the second page
...and, again, I'd like to do all of that without a form wizard, and without class-based views. (CBVs, especially, for this use case elude me a bit.) In other words: I'm looking for advice leading toward the most bulletproof and easy to read/understand solution possible. If it causes multiple hits to the database, that's fine by me. (If saving a file to the database seems anti best practice, please see this other post: Storing file content in DB
Might I be able to just create a separate view for two forms, and subclass a standard upload form, like so...
In forms.py...
class FileUploadForm(forms.Form):
files = forms.FileField(widget=forms.ClearableFileInput(attrs={'name':'files[]', 'multiple':'multiple'}))
#how to iterate over files in list or batch of files here...?
file = forms.FileField()
file = forms.FileField()
def clean_file(self):
data = self.cleaned_data["file"]
# read, parse, and create `data_dict` from file...
# subclass pre-existing UploadModelForm
**form = UploadModelForm(data_dict)**
if form.is_valid():
self.instance = form.save(commit=False)
else:
raise forms.ValidationError
return data
...and then refactor the earlier upload handler above with something like...
In views.py, substituting the following for present upload handler...
def view_for_form_one(request):
...
# the aforementioned upload handler logic, plus...
...
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
else:
# display errors
pass
...
def view_for_form_two(request):
# update and commit all data here
...?
In general, with this type of problem, I like to create single page with one <form> on it, but multiple sections which the user progresses through with javascript.
Breaking a form into a multi-part, wizard-style form series is much easier with javascript, especially if the data it produces is dynamic in nature.
If you absolutely must break it out into multiple pages, I would advise you to set up your app to be able to save the data into the database at the end of each step.
You can do that by making the metadata which the user adds at step 2 a nullable field, or even moving the metadata to a separate model.
I have a view to which I am trying to submit multiple ajax uploads via raw post data (e.g. via an octet-stream). These requests are submitted one after the other so that they process in parallel. The problem is that django thinks that only the last request is valid. For example, if I submit 5 files, the first four give:
Upload a valid image. The file you uploaded was either not an image or a corrupted image.
I'm guessing this occurs because somehow the requests overlap? And so the image isn't completely loaded before the form attempts to validate it?
And the last one works fine.
My upload view:
def upload(request):
form = UploadImageForm(request.POST, request.FILES)
print form
if form.is_valid():
# ..process image..
And my upload image form:
class UploadImageForm(forms.Form):
upload = forms.ImageField()
To submit the requests I'm using the html5uploader js pretty much right out of the box.
On a different not, have you tried https://github.com/blueimp/jQuery-File-Upload/ - is a pretty good non-flash based file uploader with progress bar.