From f0cd172cd0bccc519a6ecdf41b6a10b46ccffbcf Mon Sep 17 00:00:00 2001
From: Malcolm Tredinnick <malcolm.tredinnick@gmail.com>
Date: Sat, 15 Sep 2007 10:12:05 +0000
Subject: [PATCH] Fixed #5387 -- Added is_multipart method to forms. Original
 patch from Petr Marhhoun. Tests and documentation from Murkt.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6273 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 AUTHORS                              |  1 +
 django/newforms/forms.py             | 10 ++++++++++
 django/newforms/widgets.py           |  2 ++
 docs/newforms.txt                    | 21 +++++++++++++++++++++
 tests/regressiontests/forms/tests.py | 19 +++++++++++++++++++
 5 files changed, 53 insertions(+)

diff --git a/AUTHORS b/AUTHORS
index 18035835b2..9e6ece6eb2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -195,6 +195,7 @@ answer newbie questions, and generally made Django that much better:
     Martin Maney <http://www.chipy.org/Martin_Maney>
     masonsimon+django@gmail.com
     Manuzhai
+    Petr Marhoun <petr.marhoun@gmail.com>
     Petar Marić <http://www.petarmaric.com/>
     Nuno Mariz <nmariz@gmail.com>
     Marijn Vriens <marijn@metronomo.cl>
diff --git a/django/newforms/forms.py b/django/newforms/forms.py
index ab8729be65..2b1caddeda 100644
--- a/django/newforms/forms.py
+++ b/django/newforms/forms.py
@@ -212,6 +212,16 @@ class BaseForm(StrAndUnicode):
         """
         return self.cleaned_data
 
+    def is_multipart(self):
+        """
+        Returns True if the form needs to be multipart-encrypted, i.e. it has
+        FileInput. Otherwise, False.
+        """
+        for field in self.fields.values():
+            if field.widget.needs_multipart_form:
+                return True
+        return False
+
 class Form(BaseForm):
     "A collection of Fields, plus their associated data."
     # This is a separate class from BaseForm in order to abstract the way
diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py
index f985124389..0e7752499e 100644
--- a/django/newforms/widgets.py
+++ b/django/newforms/widgets.py
@@ -24,6 +24,7 @@ __all__ = (
 
 class Widget(object):
     is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
+    needs_multipart_form = False # Determines does this widget need multipart-encrypted form
 
     def __init__(self, attrs=None):
         if attrs is not None:
@@ -120,6 +121,7 @@ class MultipleHiddenInput(HiddenInput):
 
 class FileInput(Input):
     input_type = 'file'
+    needs_multipart_form = True
 
     def render(self, name, value, attrs=None):
         return super(FileInput, self).render(name, None, attrs=attrs)
diff --git a/docs/newforms.txt b/docs/newforms.txt
index e9e98944a0..ba0247314b 100644
--- a/docs/newforms.txt
+++ b/docs/newforms.txt
@@ -776,6 +776,27 @@ form data *and* file data::
     # Unbound form with a image field
     >>> f = ContactFormWithMugshot()
 
+Testing for multipart forms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're writing some reusable views or templates, you may not know ahead of
+time whether your form is a multipart form or not. The ``is_multipart()``
+method tells you if the form requires multipart encoding for submission::
+
+    >>> f = ContactFormWithMugshot()
+    >>> f.is_multipart()
+    True
+
+In a template, this sort of code could be useful::
+
+    {% if form.is_multipart %}
+      <form enctype="multipart/form-data" method="post" action="/foo/">
+    {% else %}
+      <form method="post" action="/foo/">
+    {% endif %}
+    {% form %}
+    </form>
+
 Subclassing forms
 -----------------
 
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index fef8361a14..b85897897f 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -3856,6 +3856,25 @@ u'sirrobin'
 <div class="errorlist"><div class="error">This field is required.</div></div>
 <p>Comment: <input type="text" name="comment" /></p>
 
+#################################
+# Test multipart-encoded form #
+#################################
+
+>>> class FormWithoutFile(Form):
+...     username = CharField()
+>>> class FormWithFile(Form):
+...     username = CharField()
+...     file = FileField()
+>>> class FormWithImage(Form):
+...     image = ImageField()
+
+>>> FormWithoutFile().is_multipart()
+False
+>>> FormWithFile().is_multipart()
+True
+>>> FormWithImage().is_multipart()
+True
+
 """
 
 __test__ = {