Following the example on the django website I'm trying to upload a file, perform checks on the contents, then feedback to the user and store the file contents.
However, I'm having trouble with the request.FILES which is always empty. My code is as follows (note the output after the print statements):
**forms.py**
class UploadFileForm(forms.Form):
data_import = forms.FileField()
class Meta:
model = Recipe
fields = ('data_import',)
**view**
def recipes_list(request):
template = 'recipes/recipes_list.html'
if request.method == 'GET':
user = request.user
queryset = Recipe.objects.filter(user=user)
form = UploadFileForm()
return render(request, 'recipes/recipes_list.html', context={'recipes': queryset, 'form': form})
elif request.method == 'POST':
print(request.FILES) # <MultiValueDict: {}>
print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['...'], 'data_import': ['recette.json']}>
form = UploadFileForm(request.POST, request.POST.data_import)
if form.is_valid():
return HttpResponseRedirect(template)
else:
print(form.errors)
**template**
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
The error I'm getting is:
<ul class="errorlist"><li>data_import<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
But i can see that the file is uploaded, and is in the request.POST.get('data_import').
I would like to run validation on the form, but I can't do this if request.FILES is empty.
I'm clearly doing something wrong, can someone please point me in the right direction?
<form method="post" enctype= multipart/form-data>
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
change your form to the upper one
Related
I have a simple Form, view and a html that renders the form. but the problem is that the form always returns form.is_valid == False.
So I have checked the cleaned data but I noticed that self.cleaned_data returns an empty list.
Here is the relevant code:
class GraphForm(forms.Form):
from_month = forms.DateField(widget=forms.Select(choices=MONTHS))
from_year = forms.DateField(widget=forms.Select(choices=YEARS))
to_month = forms.DateField(widget=forms.Select(choices=MONTHS))
to_year = forms.DateField(widget=forms.Select(choices=YEARS))
def clean(self):
return self.cleaned_data <<< will always stay be empty
def showgraph(request):
if request.method == 'POST':
form = GraphForm(request.POST)
if form.is_valid():
>>> will never happen <<<
...
...
...
else:
form = GraphForm()
return render(request, 'graph.html', {"form": form})
<form method="post">
{% csrf_token %}
{{ form.from_month }}
{{ form.from_year }}
<br>
{{ form.to_month }}
{{ form.to_year }}
<br>
<p align="center">
<button type="submit" class="btn btn-primary">send</button>
</p>
</form>
Can anyone help with this peculiar problem?
The <form> tag should have action besides method so that the submit button can work, like this.
<form action="{% url 'name_of_the_view' %}" method="post">
...
</form>
If the code doesn't reach inside form.is_valid(), then it means the form is not valid, add an else to if and print the form.errors() and return the same form to template also add form error in the template to see the errors.
def showgraph(request):
if request.method == 'POST':
form = GraphForm(request.POST)
if form.is_valid():
>>> will never happen <<<
else:
print(form.errors())
else:
form = GraphForm()
return render(request, 'graph.html', {"form": form})
Add error for each field:
<span class="text-danger">{{field.errors.as_text|cut:'* '}}</span>
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 am not getting any errors in the template. It just gives me back the form without error. Although the uploading function works fine, but if I don't give any input it doesn't give me any errors. How would I get the errors if there are in my template?
html:
{% block content %}
<form action="/{{ user.username }}/upload_photos/" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload"/>
</form>
{% endblock %}
views.py:
def upload_photos(request, user_name):
user = User.objects.get(username=unquote(user_name))
if request.method=='POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
forum = form.save(commit=False)
forum.user = user
forum.save()
return HttpResponseRedirect('/'+user.username+'/photos')
else:
form = PhotoForm()
return render(request, 'upload_photos.html',{'form':form})
else:
form = PhotoForm()
return render(request, 'upload_photos.html',{'form':form})
I've commented out the line that empties your form.
def upload_photos(request, user_name):
user = User.objects.get(username=unquote(user_name))
if request.method=='POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
forum = form.save(commit=False)
forum.user = user
forum.save()
return HttpResponseRedirect('/'+user.username+'/photos')
else:
# form = PhotoForm() Don't overwrite the submitted form.
return render(request, 'upload_photos.html',{'form':form})
else:
form = PhotoForm()
return render(request, 'upload_photos.html',{'form':form})
I have a view and its template that handles and prints a form. The form has a ChoiceField that takes a list of models as choices. Here is my view, template and form:
*views.py*
def index(request):
form = dbForm()
print "form is: ", form
return render(request, 'Directories/index.html', {'form':form})
*index.html*
<div id="content" align="center">
<form action="" method="get"> {% csrf_token %}
{{form.as_p}}
<input type="submit" value="Edit" name="_add" />
</form>
*forms.py*
model_classes = []
class dbForm(forms.Form):
model_classes_field = forms.ChoiceField(choices=models())
def models():
apps = get_app('Directories')
for model in get_models(apps):
model_classes.append( (model._meta.verbose_name, model._meta.db_table), )
return model_classes
The model choice submitted is sent to another view where a ModelForm displays the model's fields and expects data for each of the fields to be submitted. The submitted data are then stored in the database and the user is redirected back to the index to start again from the beginning. Here is the view, template and form:
*views.py*
def modelUpdate(request):
if 'update' in request.POST: # If the form has been submitted...
form_class = get_dynamic_form(request.GET['model_classes_field'])
form = form_class(request.POST)
if form.is_valid(): # All validation rules pass
row = form.save() #saves into database
return render(request, 'Directories/index.html')
else:
print "form errors: ", form.errors
return HttpResponse('ERROR -- Return to form submission')
*create.html*
<form action="" method="post"> {% csrf_token %}
{% for f_name in field_names %}
{% if not forloop.first %}
{{f_name}}: <input id="edit-{{f_name}}" type="text" name={{f_name}} /><br />
{% endif %}
{% endfor %}<br />
<input type="submit" name="update" value="Update" />
<input type="reset" name="Clear" value="Clear" />
</form>
*forms.py*
#create a ModelForm using a dynamic model
def get_dynamic_form(c_model):
model_class = get_model('Directories', c_model)
class ObjForm(forms.ModelForm ):
class Meta:
model = model_class
return ObjForm
The problem occurs when the form is redirected back to the index.html return render(request, 'Directories/index.html') after the data have been saved into the database. What happens is that the index.html does not display the form {{form.as_p}}at all. Although when i check print "form is: ", form in my server (Apache) error.log, my form is there printed as it should be.
I cannot understand why the data are not rendered in my template after the redirection occurs but still they are displayed correctly in my server log.
You should pass the form instance to your template as you do in index view. Your code shall be updated to
def modelUpdate(request):
if 'update' in request.POST: # If the form has been submitted...
form_class = get_dynamic_form(request.GET['model_classes_field'])
form = form_class(request.POST)
if form.is_valid(): # All validation rules pass
row = form.save() #saves into database
#------------------------------------------------v pass it to template
return render(request, 'Directories/index.html', {'form': form})
else:
print "form errors: ", form.errors
return HttpResponse('ERROR -- Return to form submission')
I have a ModelForm that users can submit to save information to a database. I want to extend it with a ModelFormset so that the user can view and submit the multiple of the same model forms with different information at the same time. However, my POST data isn't binding to the ModelFormset, so the ModelFormset fails as invalid upon is_valid(). I see there is data associated with request.POST.copy(), it just
views.py
def create(request):
if request.method == 'POST':
post_data = request.POST.copy()
print "POST DATA"
print post_data
for i in post_data:
print i
formSet = WorkOrder_Form(post_data)
print "FORMSET"
print formSet
if formSet.is_valid():
formSet.save()
else:
print 'INVALID'
return HttpResponseRedirect('/Shelling/')
else:
formSet = formset_factory(WorkOrder_Form, extra=1)
return render_to_response('create.html',{'WorkOrder_Form':formSet}, context_instance=RequestContext(request))
template: (create.html)
{% load url from future %}
Return to Index </li>
<br>
<br>
<form action="{% url 'create' %}" method="post"> {% csrf_token %}
{% for WorkOrder in WorkOrder_Form %}
{{ WorkOrder.as_ul }}
<br>
{% endfor %}
You are using model forms, so you should use modelformset_factory instead of formset_factory. You can create the formset class outside of the create view. Then, you need to instantiate the formset in the GET and POST branches of your view.
Putting it together, you have the following (untested, so there might be some typos!)
WorkOrderFormSet = formset_factory(WorkOrder_Form, extra=1)
def create(request):
if request.method == 'POST':
post_data = request.POST.copy()
formset = WorkOrderFormSet(data=post_data, queryset=WorkOrder.objects.none())
if formset.is_valid():
formset.save()
else:
print 'INVALID'
return HttpResponseRedirect('/Shelling/')
else:
formset = WorkOrderFormSet(queryset=WorkOrder.objects.none())
return render_to_response('create.html',{'formset':formset}, context_instance=RequestContext(request))
And in the template:
{% for form in formset %}
{{ form.as_ul }}
{% endfor %}