Right I'm learning how to do a simple image upload form to upload an image to MEDIA_ROOT. The form renders fine, I get no errors, but the file is not showing up in the MEDIA_ROOT directory. If followed the documentation example and can't get it to work and I know it is because I have not understood django file upload handeling properly. So here is my code:
forms.py
from django import forms
class UploadImageForm(forms.Form):
image = forms.ImageField()
views.py
def merchant_image_upload(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
FileUploadHandler(request.FILES['image'])
return HttpResponseRedirect('/dashboard/gallery')
else:
form = UploadImageForm()
return render_to_response('gallery.html', RequestContext(request, {'form': form}))
template file
{% extends 'base.html' %}
{% block main %}
<form action="{% url scvd.views.merchant_image_upload %}" method="post">{% csrf_token %}
{{ form.image }}
<input type="submit" value="Upload" />
</form>
{% endblock %}
Hopefully that's sufficient info to get some help. Please let me know what else I can provide. Thank you, I really appreciate the help.
You don't need to attach it to a model as Matt S states, request.FILES has all the data for the image if your form is set up correctly.
You need to make sure use enctype="multipart/form-data" in your element, as the docs state here: https://docs.djangoproject.com/en/dev/ref/forms/api/#binding-uploaded-files-to-a-form
Aside from that, read the docs about file uploads: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/
All you need is well documented there. Hope this helps!
EDIT OP requested more information on File Uploads
From the docs:
Most of the time, you'll simply pass the file data from request into
the form as described in Binding uploaded files to a form. This would
look something like:
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render_to_response('upload.html', {'form': form})
And they have an example of how you could write the handle_uploaded_file function:
def handle_uploaded_file(f):
destination = open('some/file/name.txt', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
In order to have your files uploaded and shows in request.FILES, your form MUST contain enctype="multipart/form-data" as shown below:
<form action="{% url scvd.views.merchant_image_upload %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.image }}
<input type="submit" value="Upload" />
</form>
You need to attach it to a model (as an ImageField) as it's not being saved anywhere presently. It may be handled without any issues right now but it gets discarded after the view returns.
Never mind, I didn't realize models were unnecessary.
Related
I have created a form that accepts a file upload and fetches some interesting data from the file upon POST.
However, upon refreshing the page, the form is back to its initial state but the data from the previous file remains. How do I fix it?
Here's my code:
forms.py
choices = (('all', 'all'),
('one', 'one'))
class TicketDetailForm(forms.Form):
file = forms.FileField()
type = forms.ChoiceField(choices=choices)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
views.py
def home(request):
detail = []
if request.method == 'POST':
form = TicketDetailForm(request.POST, request.FILES)
if form.is_valid():
if form.cleaned_data['type'] == 'all':
file = form.cleaned_data['file'].read()
detail.append([str(file, 'utf-8')])
# more workaround with the file
else:
form = TicketDetailForm()
return render(request, 'home.html', {'form': form,
'detail': detail})
home.html
{% extends 'base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{form.as_p}}</p>
<input type="submit" value="Submit"/>
</form>
{% if detail %}
<div class="row">
<p>The detail is as follows:</p>
{% for d in detail %}
{{ d }}
{% endif %}
</div>
{% endif %}
{% endblock %}
This is because you re-post the form when you refresh the page, since your view just renders the template even if the form is valid. The proper behaviour for a server is to always redirect after successfully submitting a POST. In other words, inside if form.is_valid() you should end by return redirect('home').
Your views should always do the following:
For a GET request, render the template
For a POST request and invalid form, render the template (with the invalid form so the user can fix errors). Hitting refresh is ok here, it will just re-submit the invalid form and therefore won't cause issues.
For a POST request and valid form, redirect, so that the last request is a GET request and the user cannot re-submit when refreshing. This also avoids the valid form to be rendered again.
I am getting the following Bootstrap exception
'Parameter "form" should contain a valid Django Form.'
when running the following code from this tutorial:
{% load bootstrap4 %}
<form action="/url/to/submit/" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Submit</button>
{% endbuttons %}
</form>
Is the second'form' in 'bootstrap_form form' supposed to reference/point to something? Is it a variable? What is a valid django form? I checked several posts and answers on this issue, but haven't been able to make sense of this error.
EDIT View code:
from django.shortcuts import render
def hello_world(request):
return render(request, 'hello_world.html', {})
I got the same problem and it takes me nearly whole day to figure out.
The Quickstart part of django-bootstrap4 is not very starter-friendly.
{% bootstrap_form form %}
The form is a parameter, which should be transfered from views.py. In your situation, form should be added to return render(request, 'hello_world.html', {})
create a file called forms.py and put following code in it.
(forms.py should be put in the same folder of views.py)
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(max_length=100)
modify views.py and add the following code:
# ...
from .forms import NameForm
# ...
def hello_world(request):
form = NameForm()
return render(request, 'hello_world.html', {'form': form})
# ...
I'm collecting data from form, processing data(right now I'm not) and displaying the result on the same HTML page from where the user submits the form.
Here is my views.py file:
def index(request):
template = 'predictor/index.html'
if request.method =='POST':
form = EvalForm(request.POST)
if form.is_valid():
text ='thank you for submitting form'
else:
text='something wrong.'
context: {
'text':text,
}
return render(request,template,context)
else:
form = EvalForm()
return render(request,template)
Here is my index.html file
<form method="POST" action="{% url 'predictor' %}">
{% csrf_token %}
//all input fields including submit button here
</form>
<div class="result">
{{ text }}
</div>
All other things like urls are configured properly.
What I'm doing wrong here?
You have typo in your code.
Should be context = {'text':text,} instead of context: {'text':text,}.
I am trying a basic example in uploading a file with django.
I tried the code from the django documentaion but I keep getting invalid form. And when I don't test the validation of the form and try to handle the file directly, I get:
MultiValueDictKeyError at /neurons/nblast
"
'file'"
P.S:
Previously, I had used a model with a FileField and set the (upload_to), but in my current case I don't need to use the model, I only need to let the user uploads his files.
This is my code:
Template
<body>
<form action="" method="post">
{{ form }}
<br>
<button class="btn btn-success" name="btn_upload">
<span class="glyphicon glyphicon-upload"></span>
<b>Upload</b>
</button>
{% csrf_token %}
</form>
</body>
Views
def test(request):
if request.method == GET:
form = UploadFileForm()
if request.method == POST:
if 'btn_upload' in request.POST:
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
else:
print 'Not Valid'
form = UploadFileForm()
return render_to_response('test.html',
{'form': form},
context_instance=RequestContext(request))
Forms:
class UploadFileForm(forms.Form):
file = forms.FileField()
Thank you very much
Have you tried looking at The Django 'File Uploads' docs , especially the enctype="multipart/form-data" attribute?
u missed this one enctype="multipart/form-data"
I'm developing a progress bar for upload files using this upload handler, it's a bit older, since 2008 have no modifications so maybe has been disregarded however this solution is used a lot around the web for this problem, specifically to monitor an upload file, the question is simple, when I make a request and I set up previously this handler, firstly, for method GET retrieve the form:
<form id="formUpload" enctype="multipart/form-data" action="/progressbar/uploadfile" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "star" %} Submit
</button>
{% endbuttons %}
csrf_token always is generated so when I make a submitfor the form, debugging, always goes to handler_raw_input before check the POST request from view so there's no csrf_token can validate against the request and throw a nice 403 csrf token error validation.
View:
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = UploadFile(file=request.FILES['file'])
instance.save()
else:
form = UploadFileForm()
return render_to_response('index.html', {'form': form}, context_instance=RequestContext(request))
How can I tell upload handler to assign csrf_token for validation? According to django documentation only uploads handlers can be modified before request.POST and reques.FILES and csrf is managing via POST forms.
Any ideas or people in same situation?
Regards!
From the documentation you referenced it looks like you have to mark the progress updates as excempt (#csrf_exempt) and the actual file handler as protected (
#csrf_protect). So for your upload handler I would try:
#csrf_exempt
def upload_progress(request):
"""
Return JSON object with information about the progress of an upload.
"""
...
#csrf_protect
def upload_file(request):
if request.method == 'POST':
...
You should obviously test this by changing the CSRF field in the form using JavaScript to make sure it fails as expected.