I am trying to use a Django 1.3 FormWizard to upload a file with 2 steps:
1. Only the FileField
2. If the file was correctly uploaded and valid (after custom validation), offer to give it a name and description.
Following the documentation, I wrote:
class CreateCheckWizard(FormWizard):
def done(self, request, form_list):
return HttpResponseRedirect('/my_checks/')
def get_template(self, step):
return ['create_check_%s.html' % step, 'create_check_1.html']
class CreateCheckForm1(forms.Form):
my_file = forms.FileField()
class CreateCheckForm2(forms.Form):
title = forms.CharField(max_length=255)
I added the multipart/form-data to the FORM tag in the template:
<form enctype="multipart/form-data" action="." method="post">
However, even if I upload a file, I get the error "This field is required."
I guess the form is created omitting the request.FILES field.
How can we change that behaviour to successfully upload files in the FormWizard?
Edit: Looking at Django source code, it indeed create the forms using form(request.POST) instead of form(request.POST, request.FILES) like it should be to handle files.
Any way to upload files without changing the source code?
This isn't possible in the Django 1.3 form wizard. From the Django form wizard docs:
Important limitation: Because the wizard uses HTML hidden fields to store data between pages, you may not include a FileField in any form except the last one
It is possible with the Django 1.4 form wizard (see handling files docs). If you're using Django 1.3, you can install the new form wizard as a separate app.
Related
I am using django-allauth for local account management. I have customized templates ,login.html and signup.html. Both of these templates are placed in templates/account/ dir and both are accessible properly.
site root i.e localhost:8000 points to index.html which includes using {% include%} both the templates on main page.
form action for signup form in signup.hmtl is set to action="{% url 'account_signup' %}" and that of login.html is set to "{% url 'account_login' %}"
Both the templates appears OK on the main page. The problem arises when I try to use these forms for sigin/login. Instead processing the POST for signup or login I am redirected to locahost:8000/accounts/signup/ for signup and localhost:8000/accounts/login/ for login. I guess I am using the right urls that is account_signup and account_login
I have all settings for allauth. Is this is the default behaviour or I'm missing some thing out? Thanking in anticipation
Well I managed to get rid of the problem after spending some hours. Just in case that some one else caughtup in the same situation I would like to share my solution. The problem was forms have been instantiated by View by using prefix SignUpForm(prefix=signupform) and for that reason allauth class AjaxCapableProcessFormViewMixin(object) (which I don't know how it works) was unable to get data from the fields and its if form.is_valid() was always false as the form has error messages dictionary was containing this field is required for all the fields in the form. Jus to test I removed Prefixing from the form instantiation and it worked but make me feel strange as these kind of hidden errors can take upto indefinite time to resolve especially for some niwbie like me
class AjaxCapableProcessFormViewMixin(object):
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
response = self.form_valid(form)
else:
response = self.form_invalid(form)
return _ajax_response(self.request, response, form=form)
Say you already have a complex HTML form, possible from a designer, front end dev, etc. Is it common practice to not use dynamic forms (based on a Django form) for complicated forms?
I want to do something like this:
1.) Create custom HTML form.
2.) Catch form data through POST request, put it in an object/dictionary.
3.) Do some manipulations with that data to get it in a format acceptable by a Django form.
4.) Pass the manipulated data in to a form object, validate it, etc...
What is a clear solution to this problem? Should I be using Django's dynamic forms for everything? If not - how do I implement the above?
EDIT:
Part of my question has to do with using the forms ONLY for validation. I don't think I made this clear. Here is what I'm trying to do:
template.html
<form method="post">
{% csrf_token %}
<input class="foo" name="bar" type="text" value=""/>
<!-- Some more fields, not rendered through Django form -->
<button type="submit">Create Object</button>
</form>
As you can see, other than the csrf_token there is no Django code here. What I am trying to do in my view is catch the data in the POST in my view, make some changes to the data, then try to bind the new data to a form (not sure if it's possible):
views.py
def my_view(request):
# Some GET code
if request.method == 'POST':
form = ImportedForm(request.POST)
form.data['foo'] = "newValue"
# Now after changing the data, validate it...
If the form and model match nicely then I'll take advantage of the ModelForm functionality.
But most of the time it is not so tidy so, most typically, I do things in about this order:
create a django form with all the field definitions
create django GET view to serve the empty form
create an html template which serves the default html/form
test the blank form
create the POST routine to call validation and reserve the validated (erroneous) form
modify the django form to validate the fields
modify the html form to serve the error messages
test the validation and error messages
modify the POST routine to handle a valid form and do whatever it should do as a result (might involve a redirect and 'thanks' view/template)
Test the whole lot
let the designer loose on the templates
In truth the designer will be involved at some points earlier along the way but in theory I just get it all to work as a "white" then add all the fancy stuff after. That includes javascript validation (ie after all the above).
I ended up doing something like this. It is ugly, and may not be the proper way to do it, but it works...
if request.method == 'POST':
try:
# Create dictionary from POST data
data = {
'foo': request.POST['foo'],
'foobar': request.POST['foobar'],
}
except:
# Handle exceptions
form = ImportedForm(data)
if form.is_valid:
# Continue to validate and save
Im trying to insert the registration-form template from django-registration in another html document.
The original Registration template it's working perfectly fine and users are saved in the DB:
This is what happend when i try to insert the registration form in any other html document using {% extend registration/myRegistrationFormTemplate.html %}. Fields are not showed and the submit button don't work.
Also, this is what happend when i try to load myRegistrationFormTemplate.html using the Jquery method .load. Fields are showed but the submit button don't work.
The question is: Why this is happening? and what's the usual procedure to do this?
You might need to use include which allows you to render the included page with the current context. However, this totally depends how you design your templates structure and how they extends other templates. This answer might explain the difference: https://stackoverflow.com/a/2863753/2074398
Thanks FallenAngel you were right, i was missing the view info. And thanks for telling me about "include" almalki, now all it's working right. In my project im using 2 forms in this view and a jquery modal window. To simplify my solution i'll only use one form. I hope this will be useful for someone.
SOLUTION:
View of the template you'll include the form
def patrimonio_view(request,
template_name='home/patrimonio.html'):
#OTHER DB QUERYS
pat = patrimonio.objects.all()
ciu = ciudad.objects.all()
if request.method == 'POST':
if "Registrar_usuario" in request.POST:
#USER REGISTRATION FORM RELATIVE
return register_usuario()
if "Registrar_comerciante" in request.POST:
#MERCHANT REGISTRATION FORM RELATIVE
return register_comerciante()
#RENDER
return render_to_response(template_name,{
'patrimonio':pat,
'ciudad':ciu,
}, context_instance=RequestContext(request))
urls.py
url(r'^patrimonio/$','patrimonio_view',
{'backend_registro_usuario': 'Hesperides.apps.accounts.regbackend_usuario.DefaultBackend','form_class_usuario':RegistrationForm_usuario}, name='vista_patrimonio'),
in the template you will include the form:
{% include "registration/registration_form_usuario.html" %}
I looked at this question:
Uploading multiple files with Django
but it did not seem to help as I have issues regarding it:
I don't want to deal with flash sessions using SWF Upload and Uploadify because I need to do uploads that only authenticated users can do.
newforms are for older versions of django, I am using 1.3
Using Django, how can I have this HTML form structure:
<form enctype="multipart/form-data" action="." method="post">
<label for="id_image_1">Image 1</label>
<input type="file" name="image[]" id="id_image_1" />
<label for="id_image_2">Image 2</label>
<input type="file" name="image[]" id="id_image_2" />
</form>
and handle it using a view?
If you have a fixed number of filefields, you could simply define a form with enough filefields, or add filefields programatically in a form's constructor. See the Django docs on File Uploads.
If you want some sort of dynamic functionality (a la gmail's "add another file"), then you could define a formset using a form with a single filefield. Display a single form initially and when you want to add another, use a little javascript to produce the new form and update the formset's management form. There are a number of snippets floating around to help you do this, though they may need some tweaking. See the Django docs on File Uploads and Formsets.
Another option may be to use a custom widget and field, though I have not reviewed or tried this.
On the off-chance you aren't aware, the name="image[]" scheme is PHP specific and has no special meaning in other languages, unless you reimplement it.
newforms is what the current forms were called before 1.0. Furthermore, if you got your form validated, http://docs.djangoproject.com/en/dev/topics/http/file-uploads/, you'll have your files as a list (tuple, probably, but sequence anyway) in request.FILES['image'], so just do:
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
for f in request.FILES['image']:
handle_uploaded_file(f)
You'll have to write handle_uploaded_file yourself, the URL explains how
I'm rather new to Django and I'm using Django 1.0.
I have this:
forms.py:
class MyForm(forms.Form):
extra_cheeze = forms.BooleanField(required=False,
initial=False,
label='Extra cheeze')
views.py:
def order_something(request):
form = MyForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
# do stuff...
The problem is that the form is not valid unless the checkbox is checked, so there doesn't seem to be a way to get a False value from the field.
As far as I can understand from the docs, it should work. It works if I add a CharField to my form...
Am I misunderstanding something here or is this a bug? (Yes, I have googled but found nothing relevant)
Update: As suggested by #Dominic Rodger, I tried adding a hidden field
dummy = forms.CharField(initial='dummy', widget=forms.widgets.HiddenInput())
and that makes the form valid. This workaround enables me to move on right now, but it would still be interesting to know if I'm misunderstanding something...
There was a bug in the code in my question. Thanks to #d0ugal for helping me spot it by including a slightly different example. The problem was here:
form = MyForm(request.POST or None) # <- PROBLEM HERE!!!!!!!!!!!!!!!!
if request.method == 'POST' and form.is_valid():
# do stuff...
The bug was that I assumed that request.POST would evaluate to True if it was a post. But since browsers don't post anything for a not-checked checkbox, and that was the only field, the POST data was an empty dictionary, which evaluates to False. This caused None to be used as initialization data, causing the form to be unbound and not valid.
#d0ugal's example does the safe thing and tests request.method first.
This also works for me on 1.1, 1.0.3 and 1.0 (I have these three Virtual environments setup). I only tested this in FireFox so if its a browser issue thats another matter but as far as I know they all handle POST data with checkboxes the same.
Here is the full code for the project so you can reproduce at your leisure and compare with yours to see the difference.
Setting up in Ubuntu
$ django-admin.py startproject testing
$ cd testing/
$ python manage.py startapp myfirst
Then in the myfirst app folder;
/myfirst/views.py
from django.shortcuts import render_to_response
from myfirst.forms import MyForm
def testing(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
result = "valid"
else:
result = "not valid"
else:
form = MyForm()
result = "no post"
return render_to_response('test.html', {'form':form, 'result':result,})
/myfirst/forms.py
from django import forms
class MyForm(forms.Form):
extra_cheeze = forms.BooleanField(required=False,initial=False,label='Extra cheeze')
/myfirst/templates/test.html
<html>
<head>
</head>
<body>
<form action="." method="POST">
{{ form }}
<input type="submit" value="test">
</form>
{{ result }}
</body>
</html>
/urls.py
from django.conf.urls.defaults import *
from myfirst.views import testing
urlpatterns = patterns('',
(r'.*', testing),
)
Then just run the project $ python manage.py runserver and browse to http://localhost:8000/. You'll actually find that required doesn't do anything with the checkbox, since you can't leave it blank - a 'blank' answer is effectively 'no'. If you want to make sure a user selects an answer have a multiple choice where the user has to select yes or no. You could force them to answer with radio buttons too.
This is not an answer, it describes the Django behaviour only.
Django 3.0.7 on Python 3.8.4rc1, Debian 10/testing.
My scenario is html <form> with more django forms.Form rendered classes inside, one of them has BooleanField only. (There are other small <forms> in page like a search form).
class OrderInvoiceTypeForm(forms.Form):
is_business = forms.BooleanField(label="business", initial=False) # with or without required=False
I submit via submit button which IS NOT in OrderInvoiceTypeForm but IS in the html .
With required=False form is always valid and is_business key is in .cleaned_data.
Without required (or with =True):
checked:
form_with_boolean.is_valid() # True
form_with_boolean.cleaned_data # {'is_business': True}
unchecked:
form_with_boolean.is_valid() # False
form_with_boolean.cleaned_data # {}
In 2nd case in dev tools I can see that browser (Chrome) doesn't send the is_business value POST variable. Adding of hidden field will not help.