12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468 |
- =================
- The forms library
- =================
- ``django.forms`` is Django's form-handling library.
- .. admonition:: Looking for oldforms?
- ``django.forms`` was once called ``newforms`` since it replaced Django's
- original form/manipulator/validation framework. The old form handling
- library is still available as `django.oldforms`_, but will be removed
- in a future version of Django.
- .. _django.oldforms: ../oldforms/
- Overview
- ========
- ``django.forms`` is intended to handle HTML form display, data processing
- (validation) and redisplay. It's what you use if you want to perform
- server-side validation for an HTML form.
- For example, if your Web site has a contact form that visitors can use to
- send you e-mail, you'd use this library to implement the display of the HTML
- form fields, along with the form validation. Any time you need to use an HTML
- ``<form>``, you can use this library.
- The library deals with these concepts:
- * **Widget** -- A class that corresponds to an HTML form widget, e.g.
- ``<input type="text">`` or ``<textarea>``. This handles rendering of the
- widget as HTML.
- * **Field** -- A class that is responsible for doing validation, e.g.
- an ``EmailField`` that makes sure its data is a valid e-mail address.
- * **Form** -- A collection of fields that knows how to validate itself and
- display itself as HTML.
- * **Media** -- A definition of the CSS and JavaScript resources that are
- required to render a form.
- The library is decoupled from the other Django components, such as the database
- layer, views and templates. It relies only on Django settings, a couple of
- ``django.utils`` helper functions and Django's internationalization hooks (but
- you're not required to be using internationalization features to use this
- library).
- Form objects
- ============
- The primary way of using the ``forms`` library is to create a form object.
- Do this by subclassing ``django.forms.Form`` and specifying the form's
- fields, in a declarative style that you'll be familiar with if you've used
- Django database models. In this section, we'll iteratively develop a form
- object that you might use to implement "contact me" functionality on your
- personal Web site.
- Start with this basic ``Form`` subclass, which we'll call ``ContactForm``::
- from django import forms
- class ContactForm(forms.Form):
- subject = forms.CharField(max_length=100)
- message = forms.CharField()
- sender = forms.EmailField()
- cc_myself = forms.BooleanField(required=False)
- A form is composed of ``Field`` objects. In this case, our form has four
- fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. We'll explain
- the different types of fields -- e.g., ``CharField`` and ``EmailField`` --
- shortly.
- Creating ``Form`` instances
- ---------------------------
- A ``Form`` instance is either **bound** to a set of data, or **unbound**.
- * If it's **bound** to a set of data, it's capable of validating that data
- and rendering the form as HTML with the data displayed in the HTML.
- * If it's **unbound**, it cannot do validation (because there's no data to
- validate!), but it can still render the blank form as HTML.
- To create an unbound ``Form`` instance, simply instantiate the class::
- >>> f = ContactForm()
- To bind data to a form, pass the data as a dictionary as the first parameter to
- your ``Form`` class constructor::
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
- >>> f = ContactForm(data)
- In this dictionary, the keys are the field names, which correspond to the
- attributes in your ``Form`` class. The values are the data you're trying
- to validate. These will usually be strings, but there's no requirement that
- they be strings; the type of data you pass depends on the ``Field``, as we'll
- see in a moment.
- If you need to distinguish between bound and unbound form instances at runtime,
- check the value of the form's ``is_bound`` attribute::
- >>> f = ContactForm()
- >>> f.is_bound
- False
- >>> f = ContactForm({'subject': 'hello'})
- >>> f.is_bound
- True
- Note that passing an empty dictionary creates a *bound* form with empty data::
- >>> f = ContactForm({})
- >>> f.is_bound
- True
- If you have a bound ``Form`` instance and want to change the data somehow, or
- if you want to bind an unbound ``Form`` instance to some data, create another
- ``Form`` instance. There is no way to change data in a ``Form`` instance. Once
- a ``Form`` instance has been created, you should consider its data immutable,
- whether it has data or not.
- Using forms to validate data
- ----------------------------
- The primary task of a ``Form`` object is to validate data. With a bound
- ``Form`` instance, call the ``is_valid()`` method to run validation and return
- a boolean designating whether the data was valid::
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
- >>> f = ContactForm(data)
- >>> f.is_valid()
- True
- Let's try with some invalid data. In this case, ``subject`` is blank (an error,
- because all fields are required by default) and ``sender`` is not a valid
- e-mail address::
- >>> data = {'subject': '',
- ... 'message': 'Hi there',
- ... 'sender': 'invalid e-mail address',
- ... 'cc_myself': True}
- >>> f = ContactForm(data)
- >>> f.is_valid()
- False
- Access the ``errors`` attribute to get a dictionary of error messages::
- >>> f.errors
- {'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']}
- In this dictionary, the keys are the field names, and the values are lists of
- Unicode strings representing the error messages. The error messages are stored
- in lists because a field can have multiple error messages.
- You can access ``errors`` without having to call ``is_valid()`` first. The
- form's data will be validated the first time either you call ``is_valid()`` or
- access ``errors``.
- The validation routines will only get called once, regardless of how many times
- you access ``errors`` or call ``is_valid()``. This means that if validation has
- side effects, those side effects will only be triggered once.
- Behavior of unbound forms
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- It's meaningless to validate a form with no data, but, for the record, here's
- what happens with unbound forms::
- >>> f = ContactForm()
- >>> f.is_valid()
- False
- >>> f.errors
- {}
- Accessing "clean" data
- ----------------------
- Each ``Field`` in a ``Form`` class is responsible not only for validating data,
- but also for "cleaning" it -- normalizing it to a consistent format. This is a
- nice feature, because it allows data for a particular field to be input in
- a variety of ways, always resulting in consistent output.
- For example, ``DateField`` normalizes input into a Python ``datetime.date``
- object. Regardless of whether you pass it a string in the format
- ``'1994-07-15'``, a ``datetime.date`` object or a number of other formats,
- ``DateField`` will always normalize it to a ``datetime.date`` object as long as
- it's valid.
- Once you've created a ``Form`` instance with a set of data and validated it,
- you can access the clean data via the ``cleaned_data`` attribute of the ``Form``
- object::
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
- >>> f = ContactForm(data)
- >>> f.is_valid()
- True
- >>> f.cleaned_data
- {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
- .. note::
- **New in Django development version** The ``cleaned_data`` attribute was
- called ``clean_data`` in earlier releases.
- Note that any text-based field -- such as ``CharField`` or ``EmailField`` --
- always cleans the input into a Unicode string. We'll cover the encoding
- implications later in this document.
- If your data does *not* validate, your ``Form`` instance will not have a
- ``cleaned_data`` attribute::
- >>> data = {'subject': '',
- ... 'message': 'Hi there',
- ... 'sender': 'invalid e-mail address',
- ... 'cc_myself': True}
- >>> f = ContactForm(data)
- >>> f.is_valid()
- False
- >>> f.cleaned_data
- Traceback (most recent call last):
- ...
- AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
- ``cleaned_data`` will always *only* contain a key for fields defined in the
- ``Form``, even if you pass extra data when you define the ``Form``. In this
- example, we pass a bunch of extra fields to the ``ContactForm`` constructor,
- but ``cleaned_data`` contains only the form's fields::
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True,
- ... 'extra_field_1': 'foo',
- ... 'extra_field_2': 'bar',
- ... 'extra_field_3': 'baz'}
- >>> f = ContactForm(data)
- >>> f.is_valid()
- True
- >>> f.cleaned_data # Doesn't contain extra_field_1, etc.
- {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
- ``cleaned_data`` will include a key and value for *all* fields defined in the
- ``Form``, even if the data didn't include a value for fields that are not
- required. In this example, the data dictionary doesn't include a value for the
- ``nick_name`` field, but ``cleaned_data`` includes it, with an empty value::
- >>> class OptionalPersonForm(Form):
- ... first_name = CharField()
- ... last_name = CharField()
- ... nick_name = CharField(required=False)
- >>> data = {'first_name': u'John', 'last_name': u'Lennon'}
- >>> f = OptionalPersonForm(data)
- >>> f.is_valid()
- True
- >>> f.cleaned_data
- {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
- In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an
- empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat
- empty values as an empty string. Each field type knows what its "blank" value
- is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For
- full details on each field's behavior in this case, see the "Empty value" note
- for each field in the "Built-in ``Field`` classes" section below.
- You can write code to perform validation for particular form fields (based on
- their name) or for the form as a whole (considering combinations of various
- fields). More information about this is in the `Custom form and field
- validation`_ section, below.
- Behavior of unbound forms
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- It's meaningless to request "cleaned" data in a form with no data, but, for the
- record, here's what happens with unbound forms::
- >>> f = ContactForm()
- >>> f.cleaned_data
- Traceback (most recent call last):
- ...
- AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
- Outputting forms as HTML
- ------------------------
- The second task of a ``Form`` object is to render itself as HTML. To do so,
- simply ``print`` it::
- >>> f = ContactForm()
- >>> print f
- <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
- <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
- <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
- <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
- If the form is bound to data, the HTML output will include that data
- appropriately. For example, if a field is represented by an
- ``<input type="text">``, the data will be in the ``value`` attribute. If a
- field is represented by an ``<input type="checkbox">``, then that HTML will
- include ``checked="checked"`` if appropriate::
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
- >>> f = ContactForm(data)
- >>> print f
- <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" /></td></tr>
- <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr>
- <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" value="foo@example.com" /></td></tr>
- <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked="checked" /></td></tr>
- This default output is a two-column HTML table, with a ``<tr>`` for each field.
- Notice the following:
- * For flexibility, the output does *not* include the ``<table>`` and
- ``</table>`` tags, nor does it include the ``<form>`` and ``</form>``
- tags or an ``<input type="submit">`` tag. It's your job to do that.
- * Each field type has a default HTML representation. ``CharField`` and
- ``EmailField`` are represented by an ``<input type="text">``.
- ``BooleanField`` is represented by an ``<input type="checkbox">``. Note
- these are merely sensible defaults; you can specify which HTML to use for
- a given field by using widgets, which we'll explain shortly.
- * The HTML ``name`` for each tag is taken directly from its attribute name
- in the ``ContactForm`` class.
- * The text label for each field -- e.g. ``'Subject:'``, ``'Message:'`` and
- ``'Cc myself:'`` is generated from the field name by converting all
- underscores to spaces and upper-casing the first letter. Again, note
- these are merely sensible defaults; you can also specify labels manually.
- * Each text label is surrounded in an HTML ``<label>`` tag, which points
- to the appropriate form field via its ``id``. Its ``id``, in turn, is
- generated by prepending ``'id_'`` to the field name. The ``id``
- attributes and ``<label>`` tags are included in the output by default, to
- follow best practices, but you can change that behavior.
- Although ``<table>`` output is the default output style when you ``print`` a
- form, other output styles are available. Each style is available as a method on
- a form object, and each rendering method returns a Unicode object.
- ``as_p()``
- ~~~~~~~~~~
- ``Form.as_p()`` renders the form as a series of ``<p>`` tags, with each ``<p>``
- containing one field::
- >>> f = ContactForm()
- >>> f.as_p()
- u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>'
- >>> print f.as_p()
- <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
- <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>
- <p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>
- <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
- ``as_ul()``
- ~~~~~~~~~~~
- ``Form.as_ul()`` renders the form as a series of ``<li>`` tags, with each
- ``<li>`` containing one field. It does *not* include the ``<ul>`` or ``</ul>``,
- so that you can specify any HTML attributes on the ``<ul>`` for flexibility::
- >>> f = ContactForm()
- >>> f.as_ul()
- u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>'
- >>> print f.as_ul()
- <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>
- <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>
- <li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>
- <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>
- ``as_table()``
- ~~~~~~~~~~~~~~
- Finally, ``Form.as_table()`` outputs the form as an HTML ``<table>``. This is
- exactly the same as ``print``. In fact, when you ``print`` a form object, it
- calls its ``as_table()`` method behind the scenes::
- >>> f = ContactForm()
- >>> f.as_table()
- u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>'
- >>> print f.as_table()
- <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
- <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
- <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
- <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
- Configuring HTML ``<label>`` tags
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- An HTML ``<label>`` tag designates which label text is associated with which
- form element. This small enhancement makes forms more usable and more accessible
- to assistive devices. It's always a good idea to use ``<label>`` tags.
- By default, the form rendering methods include HTML ``id`` attributes on the
- form elements and corresponding ``<label>`` tags around the labels. The ``id``
- attribute values are generated by prepending ``id_`` to the form field names.
- This behavior is configurable, though, if you want to change the ``id``
- convention or remove HTML ``id`` attributes and ``<label>`` tags entirely.
- Use the ``auto_id`` argument to the ``Form`` constructor to control the label
- and ``id`` behavior. This argument must be ``True``, ``False`` or a string.
- If ``auto_id`` is ``False``, then the form output will not include ``<label>``
- tags nor ``id`` attributes::
- >>> f = ContactForm(auto_id=False)
- >>> print f.as_table()
- <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr>
- <tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
- <tr><th>Sender:</th><td><input type="text" name="sender" /></td></tr>
- <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
- >>> print f.as_ul()
- <li>Subject: <input type="text" name="subject" maxlength="100" /></li>
- <li>Message: <input type="text" name="message" /></li>
- <li>Sender: <input type="text" name="sender" /></li>
- <li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
- >>> print f.as_p()
- <p>Subject: <input type="text" name="subject" maxlength="100" /></p>
- <p>Message: <input type="text" name="message" /></p>
- <p>Sender: <input type="text" name="sender" /></p>
- <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
- If ``auto_id`` is set to ``True``, then the form output *will* include
- ``<label>`` tags and will simply use the field name as its ``id`` for each form
- field::
- >>> f = ContactForm(auto_id=True)
- >>> print f.as_table()
- <tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" /></td></tr>
- <tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr>
- <tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></td></tr>
- <tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself" /></td></tr>
- >>> print f.as_ul()
- <li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></li>
- <li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li>
- <li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li>
- <li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></li>
- >>> print f.as_p()
- <p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></p>
- <p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p>
- <p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p>
- <p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></p>
- If ``auto_id`` is set to a string containing the format character ``'%s'``,
- then the form output will include ``<label>`` tags, and will generate ``id``
- attributes based on the format string. For example, for a format string
- ``'field_%s'``, a field named ``subject`` will get the ``id`` value
- ``'field_subject'``. Continuing our example::
- >>> f = ContactForm(auto_id='id_for_%s')
- >>> print f.as_table()
- <tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" /></td></tr>
- <tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr>
- <tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_for_sender" /></td></tr>
- <tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></td></tr>
- >>> print f.as_ul()
- <li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
- <li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li>
- <li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></li>
- <li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
- >>> print f.as_p()
- <p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></p>
- <p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p>
- <p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></p>
- <p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></p>
- If ``auto_id`` is set to any other true value -- such as a string that doesn't
- include ``%s`` -- then the library will act as if ``auto_id`` is ``True``.
- By default, ``auto_id`` is set to the string ``'id_%s'``.
- Normally, a colon (``:``) will be appended after any label name when a form is
- rendered. It's possible to change the colon to another character, or omit it
- entirely, using the ``label_suffix`` parameter::
- >>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
- >>> print f.as_ul()
- <li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
- <li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li>
- <li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" /></li>
- <li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
- >>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
- >>> print f.as_ul()
- <li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
- <li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li>
- <li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" /></li>
- <li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
- Note that the label suffix is added only if the last character of the
- label isn't a punctuation character (``.``, ``!``, ``?`` or ``:``)
- Notes on field ordering
- ~~~~~~~~~~~~~~~~~~~~~~~
- In the ``as_p()``, ``as_ul()`` and ``as_table()`` shortcuts, the fields are
- displayed in the order in which you define them in your form class. For
- example, in the ``ContactForm`` example, the fields are defined in the order
- ``subject``, ``message``, ``sender``, ``cc_myself``. To reorder the HTML
- output, just change the order in which those fields are listed in the class.
- How errors are displayed
- ~~~~~~~~~~~~~~~~~~~~~~~~
- If you render a bound ``Form`` object, the act of rendering will automatically
- run the form's validation if it hasn't already happened, and the HTML output
- will include the validation errors as a ``<ul class="errorlist">`` near the
- field. The particular positioning of the error messages depends on the output
- method you're using::
- >>> data = {'subject': '',
- ... 'message': 'Hi there',
- ... 'sender': 'invalid e-mail address',
- ... 'cc_myself': True}
- >>> f = ContactForm(data, auto_id=False)
- >>> print f.as_table()
- <tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr>
- <tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr>
- <tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type="text" name="sender" value="invalid e-mail address" /></td></tr>
- <tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr>
- >>> print f.as_ul()
- <li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" /></li>
- <li>Message: <input type="text" name="message" value="Hi there" /></li>
- <li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name="sender" value="invalid e-mail address" /></li>
- <li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li>
- >>> print f.as_p()
- <p><ul class="errorlist"><li>This field is required.</li></ul></p>
- <p>Subject: <input type="text" name="subject" maxlength="100" /></p>
- <p>Message: <input type="text" name="message" value="Hi there" /></p>
- <p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p>
- <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
- <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
- Customizing the error list format
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- By default, forms use ``django.forms.util.ErrorList`` to format validation
- errors. If you'd like to use an alternate class for displaying errors, you can
- pass that in at construction time::
- >>> from django.forms.util import ErrorList
- >>> class DivErrorList(ErrorList):
- ... def __unicode__(self):
- ... return self.as_divs()
- ... def as_divs(self):
- ... if not self: return u''
- ... return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
- >>> f = ContactForm(data, auto_id=False, error_class=DivErrorList)
- >>> f.as_p()
- <div class="errorlist"><div class="error">This field is required.</div></div>
- <p>Subject: <input type="text" name="subject" maxlength="100" /></p>
- <p>Message: <input type="text" name="message" value="Hi there" /></p>
- <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
- <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
- <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
- More granular output
- ~~~~~~~~~~~~~~~~~~~~
- The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for
- lazy developers -- they're not the only way a form object can be displayed.
- To display the HTML for a single field in your form, use dictionary lookup
- syntax using the field's name as the key, and print the resulting object::
- >>> f = ContactForm()
- >>> print f['subject']
- <input id="id_subject" type="text" name="subject" maxlength="100" />
- >>> print f['message']
- <input type="text" name="message" id="id_message" />
- >>> print f['sender']
- <input type="text" name="sender" id="id_sender" />
- >>> print f['cc_myself']
- <input type="checkbox" name="cc_myself" id="id_cc_myself" />
- Call ``str()`` or ``unicode()`` on the field to get its rendered HTML as a
- string or Unicode object, respectively::
- >>> str(f['subject'])
- '<input id="id_subject" type="text" name="subject" maxlength="100" />'
- >>> unicode(f['subject'])
- u'<input id="id_subject" type="text" name="subject" maxlength="100" />'
- The field-specific output honors the form object's ``auto_id`` setting::
- >>> f = ContactForm(auto_id=False)
- >>> print f['message']
- <input type="text" name="message" />
- >>> f = ContactForm(auto_id='id_%s')
- >>> print f['message']
- <input type="text" name="message" id="id_message" />
- For a field's list of errors, access the field's ``errors`` attribute. This
- is a list-like object that is displayed as an HTML ``<ul class="errorlist">``
- when printed::
- >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
- >>> f = ContactForm(data, auto_id=False)
- >>> print f['message']
- <input type="text" name="message" />
- >>> f['message'].errors
- [u'This field is required.']
- >>> print f['message'].errors
- <ul class="errorlist"><li>This field is required.</li></ul>
- >>> f['subject'].errors
- []
- >>> print f['subject'].errors
- >>> str(f['subject'].errors)
- ''
- Using forms in views and templates
- ----------------------------------
- Let's put this all together and use the ``ContactForm`` example in a Django
- view and template.
- Simple view example
- ~~~~~~~~~~~~~~~~~~~
- This example view displays the contact form by default and validates/processes
- it if accessed via a POST request::
- def contact(request):
- if request.method == 'POST':
- form = ContactForm(request.POST)
- if form.is_valid():
- # Do form processing here...
- return HttpResponseRedirect('/url/on_success/')
- else:
- form = ContactForm()
- return render_to_response('contact.html', {'form': form})
- Simple template example
- ~~~~~~~~~~~~~~~~~~~~~~~
- The template in the above view example, ``contact.html``, is responsible for
- displaying the form as HTML. To do this, we can use the techniques outlined in
- the "Outputting forms as HTML" section above.
- The simplest way to display a form's HTML is to use the variable on its own,
- like this::
- <form method="post" action="">
- <table>{{ form }}</table>
- <input type="submit" />
- </form>
- The above template code will display the form as an HTML table, using the
- ``form.as_table()`` method explained previously. This works because Django's
- template system displays an object's ``__str__()`` value, and the ``Form``
- class' ``__str__()`` method calls its ``as_table()`` method.
- The following is equivalent but a bit more explicit::
- <form method="post" action="">
- <table>{{ form.as_table }}</table>
- <input type="submit" />
- </form>
- ``form.as_ul`` and ``form.as_p`` are also available, as you may expect.
- Note that in the above two examples, we included the ``<form>``, ``<table>``
- ``<input type="submit" />``, ``</table>`` and ``</form>`` tags. The form
- convenience methods (``as_table()``, ``as_ul()`` and ``as_p()``) do not include
- that HTML.
- Complex template output
- ~~~~~~~~~~~~~~~~~~~~~~~
- As we've stressed several times, the ``as_table()``, ``as_ul()`` and ``as_p()``
- methods are just shortcuts for the common case. You can also work with the
- individual fields for complete template control over the form's design.
- The easiest way is to iterate over the form's fields, with
- ``{% for field in form %}``. For example::
- <form method="post" action="">
- <dl>
- {% for field in form %}
- <dt>{{ field.label_tag }}</dt>
- <dd>{{ field }}</dd>
- {% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
- {% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
- {% endfor %}
- </dl>
- <input type="submit" />
- </form>
- This iteration technique is useful if you want to apply the same HTML
- formatting to each field, or if you don't know the names of the form fields
- ahead of time. Note that the fields will be iterated over in the order in which
- they're defined in the ``Form`` class.
- Alternatively, you can arrange the form's fields explicitly, by name. Do that
- by accessing ``{{ form.fieldname }}``, where ``fieldname`` is the field's name.
- For example::
- <form method="post" action="">
- <ul class="myformclass">
- <li>{{ form.sender.label_tag }} {{ form.sender }}</li>
- <li class="helptext">{{ form.sender.help_text }}</li>
- {% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</ul>{% endif %}
- <li>{{ form.subject.label_tag }} {{ form.subject }}</li>
- <li class="helptext">{{ form.subject.help_text }}</li>
- {% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</ul>{% endif %}
- ...
- </ul>
- </form>
- Highlighting required fields in templates
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- It's common to show a user which fields are required. Here's an example of how
- to do that, using the above example modified to insert an asterisk after the
- label of each required field::
- <form method="post" action="">
- <dl>
- {% for field in form %}
- <dt>{{ field.label_tag }}{% if field.field.required %}*{% endif %}</dt>
- <dd>{{ field }}</dd>
- {% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
- {% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
- {% endfor %}
- </dl>
- <input type="submit" />
- </form>
- The ``{% if field.field.required %}*{% endif %}`` fragment is the relevant
- addition here. It adds the asterisk only if the field is required.
- Note that we check ``field.field.required`` and not ``field.required``. In the
- template, ``field`` is a ``forms.forms.BoundField`` instance, which holds
- the actual ``Field`` instance in its ``field`` attribute.
- Binding uploaded files to a form
- --------------------------------
- **New in Django development version**
- Dealing with forms that have ``FileField`` and ``ImageField`` fields
- is a little more complicated than a normal form.
- Firstly, in order to upload files, you'll need to make sure that your
- ``<form>`` element correctly defines the ``enctype`` as
- ``"multipart/form-data"``::
- <form enctype="multipart/form-data" method="post" action="/foo/">
- Secondly, when you use the form, you need to bind the file data. File
- data is handled separately to normal form data, so when your form
- contains a ``FileField`` and ``ImageField``, you will need to specify
- a second argument when you bind your form. So if we extend our
- ContactForm to include an ``ImageField`` called ``mugshot``, we
- need to bind the file data containing the mugshot image::
- # Bound form with an image field
- >>> from django.core.files.uploadedfile import SimpleUploadedFile
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
- >>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
- >>> f = ContactFormWithMugshot(data, file_data)
- In practice, you will usually specify ``request.FILES`` as the source
- of file data (just like you use ``request.POST`` as the source of
- form data)::
- # Bound form with an image field, data from the request
- >>> f = ContactFormWithMugshot(request.POST, request.FILES)
- Constructing an unbound form is the same as always -- just omit both
- form data *and* file data::
- # Unbound form with a image field
- >>> f = ContactFormWithMugshot()
- Testing for multipart forms
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- If you're writing 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 whether the form requires multipart encoding for submission::
- >>> f = ContactFormWithMugshot()
- >>> f.is_multipart()
- True
- Here's an example of how you might use this in a template::
- {% if form.is_multipart %}
- <form enctype="multipart/form-data" method="post" action="/foo/">
- {% else %}
- <form method="post" action="/foo/">
- {% endif %}
- {{ form }}
- </form>
- Subclassing forms
- -----------------
- If you have multiple ``Form`` classes that share fields, you can use
- subclassing to remove redundancy.
- When you subclass a custom ``Form`` class, the resulting subclass will
- include all fields of the parent class(es), followed by the fields you define
- in the subclass.
- In this example, ``ContactFormWithPriority`` contains all the fields from
- ``ContactForm``, plus an additional field, ``priority``. The ``ContactForm``
- fields are ordered first::
- >>> class ContactFormWithPriority(ContactForm):
- ... priority = forms.CharField()
- >>> f = ContactFormWithPriority(auto_id=False)
- >>> print f.as_ul()
- <li>Subject: <input type="text" name="subject" maxlength="100" /></li>
- <li>Message: <input type="text" name="message" /></li>
- <li>Sender: <input type="text" name="sender" /></li>
- <li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
- <li>Priority: <input type="text" name="priority" /></li>
- It's possible to subclass multiple forms, treating forms as "mix-ins." In this
- example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm``
- (in that order), and its field list includes the fields from the parent
- classes::
- >>> class PersonForm(Form):
- ... first_name = CharField()
- ... last_name = CharField()
- >>> class InstrumentForm(Form):
- ... instrument = CharField()
- >>> class BeatleForm(PersonForm, InstrumentForm):
- ... haircut_type = CharField()
- >>> b = BeatleForm(auto_id=False)
- >>> print b.as_ul()
- <li>First name: <input type="text" name="first_name" /></li>
- <li>Last name: <input type="text" name="last_name" /></li>
- <li>Instrument: <input type="text" name="instrument" /></li>
- <li>Haircut type: <input type="text" name="haircut_type" /></li>
- Prefixes for forms
- ------------------
- You can put several Django forms inside one ``<form>`` tag. To give each
- ``Form`` its own namespace, use the ``prefix`` keyword argument::
- >>> mother = PersonForm(prefix="mother")
- >>> father = PersonForm(prefix="father")
- >>> print mother.as_ul()
- <li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" /></li>
- <li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></li>
- >>> print father.as_ul()
- <li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
- <li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
- Fields
- ======
- When you create a ``Form`` class, the most important part is defining the
- fields of the form. Each field has custom validation logic, along with a few
- other hooks.
- Although the primary way you'll use ``Field`` classes is in ``Form`` classes,
- you can also instantiate them and use them directly to get a better idea of
- how they work. Each ``Field`` instance has a ``clean()`` method, which takes
- a single argument and either raises a ``django.forms.ValidationError``
- exception or returns the clean value::
- >>> f = forms.EmailField()
- >>> f.clean('foo@example.com')
- u'foo@example.com'
- >>> f.clean(u'foo@example.com')
- u'foo@example.com'
- >>> f.clean('invalid e-mail address')
- Traceback (most recent call last):
- ...
- ValidationError: [u'Enter a valid e-mail address.']
- If you've used Django's old forms/validation framework, take care in noticing
- this ``ValidationError`` is different than the previous ``ValidationError``.
- This one lives at ``django.forms.ValidationError`` rather than
- ``django.core.validators.ValidationError``.
- Core field arguments
- --------------------
- Each ``Field`` class constructor takes at least these arguments. Some
- ``Field`` classes take additional, field-specific arguments, but the following
- should *always* be accepted:
- ``required``
- ~~~~~~~~~~~~
- 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::
- >>> f = forms.CharField()
- >>> f.clean('foo')
- u'foo'
- >>> f.clean('')
- Traceback (most recent call last):
- ...
- ValidationError: [u'This field is required.']
- >>> f.clean(None)
- Traceback (most recent call last):
- ...
- ValidationError: [u'This field is required.']
- >>> f.clean(' ')
- u' '
- >>> f.clean(0)
- u'0'
- >>> f.clean(True)
- u'True'
- >>> f.clean(False)
- u'False'
- To specify that a field is *not* required, pass ``required=False`` to the
- ``Field`` constructor::
- >>> f = forms.CharField(required=False)
- >>> f.clean('foo')
- u'foo'
- >>> f.clean('')
- u''
- >>> f.clean(None)
- u''
- >>> f.clean(0)
- u'0'
- >>> f.clean(True)
- u'True'
- >>> f.clean(False)
- u'False'
- If a ``Field`` has ``required=False`` and you pass ``clean()`` an empty value,
- then ``clean()`` will return a *normalized* empty value rather than raising
- ``ValidationError``. For ``CharField``, this will be a Unicode empty string.
- For other ``Field`` classes, it might be ``None``. (This varies from field to
- field.)
- ``label``
- ~~~~~~~~~
- The ``label`` argument lets you specify the "human-friendly" label for this
- field. This is used when the ``Field`` is displayed in a ``Form``.
- As explained in "Outputting forms as HTML" above, the default label for a
- ``Field`` is generated from the field name by converting all underscores to
- spaces and upper-casing the first letter. Specify ``label`` if that default
- behavior doesn't result in an adequate label.
- Here's a full example ``Form`` that implements ``label`` for two of its fields.
- We've specified ``auto_id=False`` to simplify the output::
- >>> class CommentForm(forms.Form):
- ... name = forms.CharField(label='Your name')
- ... url = forms.URLField(label='Your Web site', required=False)
- ... comment = forms.CharField()
- >>> f = CommentForm(auto_id=False)
- >>> print f
- <tr><th>Your name:</th><td><input type="text" name="name" /></td></tr>
- <tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
- ``initial``
- ~~~~~~~~~~~
- The ``initial`` argument lets you specify the initial value to use when
- rendering this ``Field`` in an unbound ``Form``.
- The use-case for this is when you want to display an "empty" form in which a
- field is initialized to a particular value. For example::
- >>> class CommentForm(forms.Form):
- ... name = forms.CharField(initial='Your name')
- ... url = forms.URLField(initial='http://')
- ... comment = forms.CharField()
- >>> f = CommentForm(auto_id=False)
- >>> print f
- <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
- <tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
- You may be thinking, why not just pass a dictionary of the initial values as
- data when displaying the form? Well, if you do that, you'll trigger validation,
- and the HTML output will include any validation errors::
- >>> class CommentForm(forms.Form):
- ... name = forms.CharField()
- ... url = forms.URLField()
- ... comment = forms.CharField()
- >>> default_data = {'name': 'Your name', 'url': 'http://'}
- >>> f = CommentForm(default_data, auto_id=False)
- >>> print f
- <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
- <tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="url" value="http://" /></td></tr>
- <tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr>
- This is why ``initial`` values are only displayed for unbound forms. For bound
- forms, the HTML output will use the bound data.
- Also note that ``initial`` values are *not* used as "fallback" data in
- validation if a particular field's value is not given. ``initial`` values are
- *only* intended for initial form display::
- >>> class CommentForm(forms.Form):
- ... name = forms.CharField(initial='Your name')
- ... url = forms.URLField(initial='http://')
- ... comment = forms.CharField()
- >>> data = {'name': '', 'url': '', 'comment': 'Foo'}
- >>> f = CommentForm(data)
- >>> f.is_valid()
- False
- # The form does *not* fall back to using the initial values.
- >>> f.errors
- {'url': [u'This field is required.'], 'name': [u'This field is required.']}
- ``widget``
- ~~~~~~~~~~
- The ``widget`` argument lets you specify a ``Widget`` class to use when
- rendering this ``Field``. See `Widgets`_ below for more information.
- ``help_text``
- ~~~~~~~~~~~~~
- The ``help_text`` argument lets you specify descriptive text for this
- ``Field``. If you provide ``help_text``, it will be displayed next to the
- ``Field`` when the ``Field`` is rendered by one of the convenience ``Form``
- methods (e.g., ``as_ul()``).
- Here's a full example ``Form`` that implements ``help_text`` for two of its
- fields. We've specified ``auto_id=False`` to simplify the output::
- >>> class HelpTextContactForm(forms.Form):
- ... subject = forms.CharField(max_length=100, help_text='100 characters max.')
- ... message = forms.CharField()
- ... sender = forms.EmailField(help_text='A valid e-mail address, please.')
- ... cc_myself = forms.BooleanField(required=False)
- >>> f = HelpTextContactForm(auto_id=False)
- >>> print f.as_table()
- <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max.</td></tr>
- <tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
- <tr><th>Sender:</th><td><input type="text" name="sender" /><br />A valid e-mail address, please.</td></tr>
- <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
- >>> print f.as_ul()
- <li>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</li>
- <li>Message: <input type="text" name="message" /></li>
- <li>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</li>
- <li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
- >>> print f.as_p()
- <p>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</p>
- <p>Message: <input type="text" name="message" /></p>
- <p>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</p>
- <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
- ``error_messages``
- ~~~~~~~~~~~~~~~~~~
- **New in Django development version**
- The ``error_messages`` argument lets you override the default messages that the
- field will raise. Pass in a dictionary with keys matching the error messages you
- want to override. For example, here is the default error message::
- >>> generic = forms.CharField()
- >>> generic.clean('')
- Traceback (most recent call last):
- ...
- ValidationError: [u'This field is required.']
- And here is a custom error message::
- >>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
- >>> name.clean('')
- Traceback (most recent call last):
- ...
- ValidationError: [u'Please enter your name']
- In the `built-in Field classes`_ section below, each ``Field`` defines the
- error message keys it uses.
- Dynamic initial values
- ----------------------
- The ``initial`` argument to ``Field`` (explained above) lets you hard-code the
- initial value for a ``Field`` -- but what if you want to declare the initial
- value at runtime? For example, you might want to fill in a ``username`` field
- with the username of the current session.
- To accomplish this, use the ``initial`` argument to a ``Form``. This argument,
- if given, should be a dictionary mapping field names to initial values. Only
- include the fields for which you're specifying an initial value; it's not
- necessary to include every field in your form. For example::
- >>> class CommentForm(forms.Form):
- ... name = forms.CharField()
- ... url = forms.URLField()
- ... comment = forms.CharField()
- >>> f = CommentForm(initial={'name': 'your username'}, auto_id=False)
- >>> print f
- <tr><th>Name:</th><td><input type="text" name="name" value="your username" /></td></tr>
- <tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
- >>> f = CommentForm(initial={'name': 'another username'}, auto_id=False)
- >>> print f
- <tr><th>Name:</th><td><input type="text" name="name" value="another username" /></td></tr>
- <tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
- Just like the ``initial`` parameter to ``Field``, these values are only
- displayed for unbound forms, and they're not used as fallback values if a
- particular value isn't provided.
- Finally, note that if a ``Field`` defines ``initial`` *and* you include
- ``initial`` when instantiating the ``Form``, then the latter ``initial`` will
- have precedence. In this example, ``initial`` is provided both at the field
- level and at the form instance level, and the latter gets precedence::
- >>> class CommentForm(forms.Form):
- ... name = forms.CharField(initial='class')
- ... url = forms.URLField()
- ... comment = forms.CharField()
- >>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
- >>> print f
- <tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr>
- <tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
- Built-in ``Field`` classes
- --------------------------
- Naturally, the ``forms`` library comes with a set of ``Field`` classes that
- represent common validation needs. This section documents each built-in field.
- For each field, we describe the default widget used if you don't specify
- ``widget``. We also specify the value returned when you provide an empty value
- (see the section on ``required`` above to understand what that means).
- ``BooleanField``
- ~~~~~~~~~~~~~~~~
- * Default widget: ``CheckboxInput``
- * Empty value: ``False``
- * Normalizes to: A Python ``True`` or ``False`` value.
- * Validates that the check box is checked (i.e. the value is ``True``) if
- the field has ``required=True``.
- * Error message keys: ``required``
- **New in Django development version:** The empty value for a ``CheckboxInput``
- (and hence the standard ``BooleanField``) has changed to return ``False``
- instead of ``None`` in the development version.
- .. note::
- Since all ``Field`` subclasses have ``required=True`` by default, the
- validation condition here is important. If you want to include a checkbox
- in your form that can be either checked or unchecked, you must remember to
- pass in ``required=False`` when creating the ``BooleanField``.
- ``CharField``
- ~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``''`` (an empty string)
- * Normalizes to: A Unicode object.
- * Validates ``max_length`` or ``min_length``, if they are provided.
- Otherwise, all inputs are valid.
- * Error message keys: ``required``, ``max_length``, ``min_length``
- Has two optional arguments for validation, ``max_length`` and ``min_length``.
- If provided, these arguments ensure that the string is at most or at least the
- given length.
- ``ChoiceField``
- ~~~~~~~~~~~~~~~
- * Default widget: ``Select``
- * Empty value: ``''`` (an empty string)
- * Normalizes to: A Unicode object.
- * Validates that the given value exists in the list of choices.
- * Error message keys: ``required``, ``invalid_choice``
- Takes one extra argument, ``choices``, which is an iterable (e.g., a list or
- tuple) of 2-tuples to use as choices for this field. This argument accepts
- the same formats as the ``choices`` argument to a model field. See the
- `model API documentation on choices`_ for more details.
- .. _model API documentation on choices: ../model-api#choices
- ``DateField``
- ~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``None``
- * Normalizes to: A Python ``datetime.date`` object.
- * Validates that the given value is either a ``datetime.date``,
- ``datetime.datetime`` or string formatted in a particular date format.
- * Error message keys: ``required``, ``invalid``
- Takes one optional argument, ``input_formats``, which is a list of formats used
- to attempt to convert a string to a valid ``datetime.date`` object.
- If no ``input_formats`` argument is provided, the default input formats are::
- '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
- '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
- '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
- '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
- '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
- ``DateTimeField``
- ~~~~~~~~~~~~~~~~~
- * Default widget: ``DateTimeInput``
- * Empty value: ``None``
- * Normalizes to: A Python ``datetime.datetime`` object.
- * Validates that the given value is either a ``datetime.datetime``,
- ``datetime.date`` or string formatted in a particular datetime format.
- * Error message keys: ``required``, ``invalid``
- Takes one optional argument, ``input_formats``, which is a list of formats used
- to attempt to convert a string to a valid ``datetime.datetime`` object.
- If no ``input_formats`` argument is provided, the default input formats are::
- '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
- '%Y-%m-%d %H:%M', # '2006-10-25 14:30'
- '%Y-%m-%d', # '2006-10-25'
- '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
- '%m/%d/%Y %H:%M', # '10/25/2006 14:30'
- '%m/%d/%Y', # '10/25/2006'
- '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
- '%m/%d/%y %H:%M', # '10/25/06 14:30'
- '%m/%d/%y', # '10/25/06'
- **New in Django development version:** The ``DateTimeField`` used to use a
- ``TextInput`` widget by default. This has now changed.
- ``DecimalField``
- ~~~~~~~~~~~~~~~~
- **New in Django development version**
- * Default widget: ``TextInput``
- * Empty value: ``None``
- * Normalizes to: A Python ``decimal``.
- * Validates that the given value is a decimal. Leading and trailing
- whitespace is ignored.
- * Error message keys: ``required``, ``invalid``, ``max_value``,
- ``min_value``, ``max_digits``, ``max_decimal_places``,
- ``max_whole_digits``
- Takes four optional arguments: ``max_value``, ``min_value``, ``max_digits``,
- and ``decimal_places``. The first two define the limits for the fields value.
- ``max_digits`` is the maximum number of digits (those before the decimal
- point plus those after the decimal point, with leading zeros stripped)
- permitted in the value, whilst ``decimal_places`` is the maximum number of
- decimal places permitted.
- ``EmailField``
- ~~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``''`` (an empty string)
- * Normalizes to: A Unicode object.
- * Validates that the given value is a valid e-mail address, using a
- moderately complex regular expression.
- * Error message keys: ``required``, ``invalid``
- Has two optional arguments for validation, ``max_length`` and ``min_length``.
- If provided, these arguments ensure that the string is at most or at least the
- given length.
- ``FileField``
- ~~~~~~~~~~~~~
- **New in Django development version**
- * Default widget: ``FileInput``
- * Empty value: ``None``
- * Normalizes to: An ``UploadedFile`` object that wraps the file content
- and file name into a single object.
- * Validates that non-empty file data has been bound to the form.
- * Error message keys: ``required``, ``invalid``, ``missing``, ``empty``
- To learn more about the ``UploadedFile`` object, see the `file uploads documentation`_.
- When you use a ``FileField`` in a form, you must also remember to
- `bind the file data to the form`_.
- .. _file uploads documentation: ../upload_handling/
- .. _`bind the file data to the form`: `Binding uploaded files to a form`_
- ``FilePathField``
- ~~~~~~~~~~~~~~~~~
- **New in Django development version**
- * Default widget: ``Select``
- * Empty value: ``None``
- * Normalizes to: A unicode object
- * Validates that the selected choice exists in the list of choices.
- * Error message keys: ``required``, ``invalid_choice``
- The field allows choosing from files inside a certain directory. It takes three
- extra arguments:
- ============== ========== ===============================================
- Argument Required? Description
- ============== ========== ===============================================
- ``path`` Yes The absolute path to the directory whose
- contents you want listed. This directory must
- exist.
- ``recursive`` No If ``False`` (the default) only the direct
- contents of ``path`` will be offered as choices.
- If ``True``, the directory will be descended
- into recursively and all descendants will be
- listed as choices.
- ``match`` No A regular expression pattern; only files with
- names matching this expression will be allowed
- as choices.
- ============== ========== ===============================================
- ``FloatField``
- ~~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``None``
- * Normalizes to: A Python float.
- * Validates that the given value is an float. Leading and trailing
- whitespace is allowed, as in Python's ``float()`` function.
- * Error message keys: ``required``, ``invalid``, ``max_value``,
- ``min_value``
- Takes two optional arguments for validation, ``max_value`` and ``min_value``.
- These control the range of values permitted in the field.
- ``ImageField``
- ~~~~~~~~~~~~~~
- **New in Django development version**
- * Default widget: ``FileInput``
- * Empty value: ``None``
- * Normalizes to: An ``UploadedFile`` object that wraps the file content
- and file name into a single object.
- * Validates that file data has been bound to the form, and that the
- file is of an image format understood by PIL.
- * Error message keys: ``required``, ``invalid``, ``missing``, ``empty``,
- ``invalid_image``
- Using an ImageField requires that the `Python Imaging Library`_ is installed.
- When you use an ``ImageField`` in a form, you must also remember to
- `bind the file data to the form`_.
- .. _Python Imaging Library: http://www.pythonware.com/products/pil/
- ``IntegerField``
- ~~~~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``None``
- * Normalizes to: A Python integer or long integer.
- * Validates that the given value is an integer. Leading and trailing
- whitespace is allowed, as in Python's ``int()`` function.
- * Error message keys: ``required``, ``invalid``, ``max_value``,
- ``min_value``
- Takes two optional arguments for validation, ``max_value`` and ``min_value``.
- These control the range of values permitted in the field.
- ``IPAddressField``
- ~~~~~~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``''`` (an empty string)
- * Normalizes to: A Unicode object.
- * Validates that the given value is a valid IPv4 address, using a regular
- expression.
- * Error message keys: ``required``, ``invalid``
- ``MultipleChoiceField``
- ~~~~~~~~~~~~~~~~~~~~~~~
- * Default widget: ``SelectMultiple``
- * Empty value: ``[]`` (an empty list)
- * Normalizes to: A list of Unicode objects.
- * Validates that every value in the given list of values exists in the list
- of choices.
- * Error message keys: ``required``, ``invalid_choice``, ``invalid_list``
- Takes one extra argument, ``choices``, which is an iterable (e.g., a list or
- tuple) of 2-tuples to use as choices for this field. This argument accepts
- the same formats as the ``choices`` argument to a model field. See the
- `model API documentation on choices`_ for more details.
- ``NullBooleanField``
- ~~~~~~~~~~~~~~~~~~~~
- * Default widget: ``NullBooleanSelect``
- * Empty value: ``None``
- * Normalizes to: A Python ``True``, ``False`` or ``None`` value.
- * Validates nothing (i.e., it never raises a ``ValidationError``).
- ``RegexField``
- ~~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``''`` (an empty string)
- * Normalizes to: A Unicode object.
- * Validates that the given value matches against a certain regular
- expression.
- * Error message keys: ``required``, ``invalid``
- Takes one required argument, ``regex``, which is a regular expression specified
- either as a string or a compiled regular expression object.
- Also takes the following optional arguments:
- ====================== =====================================================
- Argument Description
- ====================== =====================================================
- ``max_length`` Ensures the string has at most this many characters.
- ``min_length`` Ensures the string has at least this many characters.
- ====================== =====================================================
- The optional argument ``error_message`` is also accepted for backwards
- compatibility. The preferred way to provide an error message is to use the
- ``error_messages`` argument, passing a dictionary with ``'invalid'`` as a key
- and the error message as the value.
- ``TimeField``
- ~~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``None``
- * Normalizes to: A Python ``datetime.time`` object.
- * Validates that the given value is either a ``datetime.time`` or string
- formatted in a particular time format.
- * Error message keys: ``required``, ``invalid``
- Takes one optional argument, ``input_formats``, which is a list of formats used
- to attempt to convert a string to a valid ``datetime.time`` object.
- If no ``input_formats`` argument is provided, the default input formats are::
- '%H:%M:%S', # '14:30:59'
- '%H:%M', # '14:30'
- ``URLField``
- ~~~~~~~~~~~~
- * Default widget: ``TextInput``
- * Empty value: ``''`` (an empty string)
- * Normalizes to: A Unicode object.
- * Validates that the given value is a valid URL.
- * Error message keys: ``required``, ``invalid``, ``invalid_link``
- Takes the following optional arguments:
- ======================== =====================================================
- Argument Description
- ======================== =====================================================
- ``max_length`` Ensures the string has at most this many characters.
- ``min_length`` Ensures the string has at least this many characters.
- ``verify_exists`` If ``True``, the validator will attempt to load the
- given URL, raising ``ValidationError`` if the page
- gives a 404. Defaults to ``False``.
- ``validator_user_agent`` String used as the user-agent used when checking for
- a URL's existence. Defaults to the value of the
- ``URL_VALIDATOR_USER_AGENT`` setting.
- ======================== =====================================================
- Slightly complex built-in ``Field`` classes
- -------------------------------------------
- The following are not yet documented here. See the unit tests, linked-to from
- the bottom of this document, for examples of their use.
- ``ComboField``
- ~~~~~~~~~~~~~~
- ``MultiValueField``
- ~~~~~~~~~~~~~~~~~~~
- ``SplitDateTimeField``
- ~~~~~~~~~~~~~~~~~~~~~~
- Fields which handle relationships
- ---------------------------------
- For representing relationships between models, two fields are
- provided which can derive their choices from a ``QuerySet``, and which
- place one or more model objects into the ``cleaned_data`` dictionary
- of forms in which they're used. Both of these fields have an
- additional required argument:
- ``queryset``
- A ``QuerySet`` of model objects from which the choices for the
- field will be derived, and which will be used to validate the
- user's selection.
- ``ModelChoiceField``
- ~~~~~~~~~~~~~~~~~~~~
- Allows the selection of a single model object, suitable for
- representing a foreign key.
- The ``__unicode__`` method of the model will be called to generate
- string representations of the objects for use in the field's choices;
- to provide customized representations, subclass ``ModelChoiceField``
- and override ``label_from_instance``. This method will receive a model
- object, and should return a string suitable for representing it. For
- example::
- class MyModelChoiceField(ModelChoiceField):
- def label_from_instance(self, obj):
- return "My Object #%i" % obj.id
- ``ModelMultipleChoiceField``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Allows the selection of one or more model objects, suitable for
- representing a many-to-many relation. As with ``ModelChoiceField``,
- you can use ``label_from_instance`` to customize the object
- representations.
- Creating custom fields
- ----------------------
- If the built-in ``Field`` classes don't meet your needs, you can easily create
- custom ``Field`` classes. To do this, just create a subclass of
- ``django.forms.Field``. Its only requirements are that it implement a
- ``clean()`` method and that its ``__init__()`` method accept the core arguments
- mentioned above (``required``, ``label``, ``initial``, ``widget``,
- ``help_text``).
- Custom form and field validation
- ---------------------------------
- Form validation happens when the data is cleaned. If you want to customize
- this process, there are various places you can change, each one serving a
- different purpose. Three types of cleaning methods are run during form
- processing. These are normally executed when you call the ``is_valid()``
- method on a form. There are other things that can trigger cleaning and
- validation (accessing the ``errors`` attribute or calling ``full_clean()``
- directly), but normally they won't be needed.
- In general, any cleaning method can raise ``ValidationError`` if there is a
- problem with the data it is processing, passing the relevant error message to
- the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the
- method should return the cleaned (normalized) data as a Python object.
- If you detect multiple errors during a cleaning method and wish to signal all
- of them to the form submitter, it is possible to pass a list of errors to the
- ``ValidationError`` constructor.
- The three types of cleaning methods are:
- * The ``clean()`` method on a Field subclass. This is responsible
- for cleaning the data in a way that is generic for that type of field.
- For example, a FloatField will turn the data into a Python ``float`` or
- raise a ``ValidationError``.
- * The ``clean_<fieldname>()`` method in a form subclass -- where
- ``<fieldname>`` is replaced with the name of the form field attribute.
- This method does any cleaning that is specific to that particular
- attribute, unrelated to the type of field that it is. This method is not
- passed any parameters. You will need to look up the value of the field
- in ``self.cleaned_data`` and remember that it will be a Python object
- at this point, not the original string submitted in the form (it will be
- in ``cleaned_data`` because the general field ``clean()`` method, above,
- has already cleaned the data once).
- For example, if you wanted to validate that the contents of a
- ``CharField`` called ``serialnumber`` was unique,
- ``clean_serialnumber()`` would be the right place to do this. You don't
- need a specific field (it's just a ``CharField``), but you want a
- formfield-specific piece of validation and, possibly,
- cleaning/normalizing the data.
- * The Form subclass's ``clean()`` method. This method can perform
- any validation that requires access to multiple fields from the form at
- once. This is where you might put in things to check that if field ``A``
- is supplied, field ``B`` must contain a valid e-mail address and the
- like. The data that this method returns is the final ``cleaned_data``
- attribute for the form, so don't forget to return the full list of
- cleaned data if you override this method (by default, ``Form.clean()``
- just returns ``self.cleaned_data``).
- Note that any errors raised by your ``Form.clean()`` override will not
- be associated with any field in particular. They go into a special
- "field" (called ``__all__``), which you can access via the
- ``non_field_errors()`` method if you need to.
- These methods are run in the order given above, one field at a time. That is,
- for each field in the form (in the order they are declared in the form
- definition), the ``Field.clean()`` method (or its override) is run, then
- ``clean_<fieldname>()``. Finally, once those two methods are run for every
- field, the ``Form.clean()`` method, or its override, is executed.
- As mentioned above, any of these methods can raise a ``ValidationError``. For
- any field, if the ``Field.clean()`` method raises a ``ValidationError``, any
- field-specific cleaning method is not called. However, the cleaning methods
- for all remaining fields are still executed.
- The ``clean()`` method for the ``Form`` class or subclass is always run. If
- that method raises a ``ValidationError``, ``cleaned_data`` will be an empty
- dictionary.
- The previous paragraph means that if you are overriding ``Form.clean()``, you
- should iterate through ``self.cleaned_data.items()``, possibly considering the
- ``_errors`` dictionary attribute on the form as well. In this way, you will
- already know which fields have passed their individual validation requirements.
- A simple example
- ~~~~~~~~~~~~~~~~
- Here's a simple example of a custom field that validates its input is a string
- containing comma-separated e-mail addresses, with at least one address. We'll
- keep it simple and assume e-mail validation is contained in a function called
- ``is_valid_email()``. The full class::
- from django import forms
- class MultiEmailField(forms.Field):
- def clean(self, value):
- if not value:
- raise forms.ValidationError('Enter at least one e-mail address.')
- emails = value.split(',')
- for email in emails:
- if not is_valid_email(email):
- raise forms.ValidationError('%s is not a valid e-mail address.' % email)
- return emails
- Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use
- this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``,
- like so::
- class ContactForm(forms.Form):
- subject = forms.CharField(max_length=100)
- message = forms.CharField()
- senders = MultiEmailField()
- cc_myself = forms.BooleanField(required=False)
- Widgets
- =======
- A widget is Django's representation of a HTML input element. The widget
- handles the rendering of the HTML, and the extraction of data from a GET/POST
- dictionary that corresponds to the widget.
- Django provides a representation of all the basic HTML widgets, plus some
- commonly used groups of widgets:
- ============================ ===========================================
- Widget HTML Equivalent
- ============================ ===========================================
- ``TextInput`` ``<input type='text' ...``
- ``PasswordInput`` ``<input type='password' ...``
- ``HiddenInput`` ``<input type='hidden' ...``
- ``MultipleHiddenInput`` Multiple ``<input type='hidden' ...``
- instances.
- ``FileInput`` ``<input type='file' ...``
- ``DateTimeInput`` ``<input type='text' ...``
- ``Textarea`` ``<textarea>...</textarea>``
- ``CheckboxInput`` ``<input type='checkbox' ...``
- ``Select`` ``<select><option ...``
- ``NullBooleanSelect`` Select widget with options 'Unknown',
- 'Yes' and 'No'
- ``SelectMultiple`` ``<select multiple='multiple'><option ...``
- ``RadioSelect`` ``<ul><li><input type='radio' ...``
- ``CheckboxSelectMultiple`` ``<ul><li><input type='checkbox' ...``
- ``MultiWidget`` Wrapper around multiple other widgets
- ``SplitDateTimeWidget`` Wrapper around two ``TextInput`` widgets:
- one for the Date, and one for the Time.
- ============================ ===========================================
- **New in Django development version:** The ``DateTimeInput`` has been added
- since the last release.
- Specifying widgets
- ------------------
- Whenever you specify a field on a form, Django will use a default widget
- that is appropriate to the type of data that is to be displayed. To find
- which widget is used on which field, see the documentation for the
- built-in Field classes.
- However, if you want to use a different widget for a field, you can -
- just use the 'widget' argument on the field definition. For example::
- class CommentForm(forms.Form):
- name = forms.CharField()
- url = forms.URLField()
- comment = forms.CharField(widget=forms.Textarea)
- This would specify a form with a comment that uses a larger Textarea widget,
- rather than the default TextInput widget.
- Customizing widget instances
- ----------------------------
- When Django renders a widget as HTML, it only renders the bare minimum
- HTML - Django doesn't add a class definition, or any other widget-specific
- attributes. This means that all 'TextInput' widgets will appear the same
- on your Web page.
- If you want to make one widget look different to another, you need to
- specify additional attributes for each widget. When you specify a
- widget, you can provide a list of attributes that will be added to the
- rendered HTML for the widget.
- For example, take the following simple form::
- class CommentForm(forms.Form):
- name = forms.CharField()
- url = forms.URLField()
- comment = forms.CharField()
- This form will include three default TextInput widgets, with default rendering -
- no CSS class, no extra attributes. This means that the input boxes provided for
- each widget will be rendered exactly the same::
- >>> f = CommentForm(auto_id=False)
- >>> f.as_table()
- <tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
- <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
- On a real Web page, you probably don't want every widget to look the same. You
- might want a larger input element for the comment, and you might want the
- 'name' widget to have some special CSS class. To do this, you specify a
- custom widget for your fields, and specify some attributes to use
- when rendering those widgets::
- class CommentForm(forms.Form):
- name = forms.CharField(
- widget=forms.TextInput(attrs={'class':'special'}))
- url = forms.URLField()
- comment = forms.CharField(
- widget=forms.TextInput(attrs={'size':'40'}))
- Django will then include the extra attributes in the rendered output::
- >>> f = CommentForm(auto_id=False)
- >>> f.as_table()
- <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
- <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
- <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
- Custom Widgets
- --------------
- When you start to write a lot of forms, you will probably find that you will
- reuse certain sets of widget attributes over and over again. Rather than
- repeat these attribute definitions every time you need them, Django allows
- you to capture those definitions as a custom widget.
- For example, if you find that you are including a lot of comment fields on
- forms, you could capture the idea of a ``TextInput`` with a specific
- default ``size`` attribute as a custom extension to the ``TextInput`` widget::
- class CommentWidget(forms.TextInput):
- def __init__(self, *args, **kwargs):
- attrs = kwargs.setdefault('attrs',{})
- if 'size' not in attrs:
- attrs['size'] = 40
- super(CommentWidget, self).__init__(*args, **kwargs)
- We allow the ``size`` attribute to be overridden by the user, but, by default,
- this widget will behave as if ``attrs={'size': 40}`` was always passed into the
- constructor.
- Then you can use this widget in your forms::
- class CommentForm(forms.Form):
- name = forms.CharField()
- url = forms.URLField()
- comment = forms.CharField(widget=CommentWidget)
- You can even customize your custom widget, in the same way as you would
- any other widget. Adding a once-off class to your ``CommentWidget`` is as
- simple as adding an attribute definition::
- class CommentForm(forms.Form):
- name = forms.CharField(max_length=20)
- url = forms.URLField()
- comment = forms.CharField(
- widget=CommentWidget(attrs={'class': 'special'}))
- Django also makes it easy to specify a custom field type that uses your custom
- widget. For example, you could define a customized field type for comments
- by defining::
- class CommentInput(forms.CharField):
- widget = CommentWidget
- You can then use this field whenever you have a form that requires a comment::
- class CommentForm(forms.Form):
- name = forms.CharField()
- url = forms.URLField()
- comment = CommentInput()
- Generating forms for models
- ===========================
- The prefered way of generating forms that work with models is explained in the
- `ModelForms documentation`_.
- .. _ModelForms documentation: ../modelforms/
- Media
- =====
- Rendering an attractive and easy-to-use web form requires more than just
- HTML - it also requires CSS stylesheets, and if you want to use fancy
- "Web2.0" widgets, you may also need to include some JavaScript on each
- page. The exact combination of CSS and JavaScript that is required for
- any given page will depend upon the widgets that are in use on that page.
- This is where Django media definitions come in. Django allows you to
- associate different media files with the forms and widgets that require
- that media. For example, if you want to use a calendar to render DateFields,
- you can define a custom Calendar widget. This widget can then be associated
- with the CSS and JavaScript that is required to render the calendar. When
- the Calendar widget is used on a form, Django is able to identify the CSS and
- JavaScript files that are required, and provide the list of file names
- in a form suitable for easy inclusion on your web page.
- .. admonition:: Media and Django Admin
- The Django Admin application defines a number of customized widgets
- for calendars, filtered selections, and so on. These widgets define
- media requirements, and the Django Admin uses the custom widgets
- in place of the Django defaults. The Admin templates will only include
- those media files that are required to render the widgets on any
- given page.
- If you like the widgets that the Django Admin application uses,
- feel free to use them in your own application! They're all stored
- in ``django.contrib.admin.widgets``.
- .. admonition:: Which JavaScript toolkit?
- Many JavaScript toolkits exist, and many of them include widgets (such
- as calendar widgets) that can be used to enhance your application.
- Django has deliberately avoided blessing any one JavaScript toolkit.
- Each toolkit has its own relative strengths and weaknesses - use
- whichever toolkit suits your requirements. Django is able to integrate
- with any JavaScript toolkit.
- Media as a static definition
- ----------------------------
- The easiest way to define media is as a static definition. Using this method,
- the media declaration is an inner class. The properties of the inner class
- define the media requirements.
- Here's a simple example::
- class CalendarWidget(forms.TextInput):
- class Media:
- css = {
- 'all': ('pretty.css',)
- }
- js = ('animations.js', 'actions.js')
- This code defines a ``CalendarWidget``, which will be based on ``TextInput``.
- Every time the CalendarWidget is used on a form, that form will be directed
- to include the CSS file ``pretty.css``, and the JavaScript files
- ``animations.js`` and ``actions.js``.
- This static media definition is converted at runtime into a widget property
- named ``media``. The media for a CalendarWidget instance can be retrieved
- through this property::
- >>> w = CalendarWidget()
- >>> print w.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- Here's a list of all possible ``Media`` options. There are no required options.
- ``css``
- ~~~~~~~
- A dictionary describing the CSS files required for various forms of output
- media.
- The values in the dictionary should be a tuple/list of file names. See
- `the section on media paths`_ for details of how to specify paths to media
- files.
- .. _the section on media paths: `Paths in media definitions`_
- The keys in the dictionary are the output media types. These are the same
- types accepted by CSS files in media declarations: 'all', 'aural', 'braille',
- 'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. If
- you need to have different stylesheets for different media types, provide
- a list of CSS files for each output medium. The following example would
- provide two CSS options -- one for the screen, and one for print::
- class Media:
- css = {
- 'screen': ('pretty.css',),
- 'print': ('newspaper.css',)
- }
- If a group of CSS files are appropriate for multiple output media types,
- the dictionary key can be a comma separated list of output media types.
- In the following example, TV's and projectors will have the same media
- requirements::
- class Media:
- css = {
- 'screen': ('pretty.css',),
- 'tv,projector': ('lo_res.css',),
- 'print': ('newspaper.css',)
- }
- If this last CSS definition were to be rendered, it would become the following HTML::
- <link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
- <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
- <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
- ``js``
- ~~~~~~
- A tuple describing the required JavaScript files. See
- `the section on media paths`_ for details of how to specify paths to media
- files.
- ``extend``
- ~~~~~~~~~~
- A boolean defining inheritance behavior for media declarations.
- By default, any object using a static media definition will inherit all the
- media associated with the parent widget. This occurs regardless of how the
- parent defines its media requirements. For example, if we were to extend our
- basic Calendar widget from the example above::
- class FancyCalendarWidget(CalendarWidget):
- class Media:
- css = {
- 'all': ('fancy.css',)
- }
- js = ('whizbang.js',)
- >>> w = FancyCalendarWidget()
- >>> print w.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
- The FancyCalendar widget inherits all the media from it's parent widget. If
- you don't want media to be inherited in this way, add an ``extend=False``
- declaration to the media declaration::
- class FancyCalendar(Calendar):
- class Media:
- extend = False
- css = {
- 'all': ('fancy.css',)
- }
- js = ('whizbang.js',)
- >>> w = FancyCalendarWidget()
- >>> print w.media
- <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
- If you require even more control over media inheritance, define your media
- using a `dynamic property`_. Dynamic properties give you complete control over
- which media files are inherited, and which are not.
- .. _dynamic property: `Media as a dynamic property`_
- Media as a dynamic property
- ---------------------------
- If you need to perform some more sophisticated manipulation of media
- requirements, you can define the media property directly. This is done
- by defining a model property that returns an instance of ``forms.Media``.
- The constructor for ``forms.Media`` accepts ``css`` and ``js`` keyword
- arguments in the same format as that used in a static media definition.
- For example, the static media definition for our Calendar Widget could
- also be defined in a dynamic fashion::
- class CalendarWidget(forms.TextInput):
- def _media(self):
- return forms.Media(css={'all': ('pretty.css',)},
- js=('animations.js', 'actions.js'))
- media = property(_media)
- See the section on `Media objects`_ for more details on how to construct
- return values for dynamic media properties.
- Paths in media definitions
- --------------------------
- Paths used to specify media can be either relative or absolute. If a path
- starts with '/', 'http://' or 'https://', it will be interpreted as an absolute
- path, and left as-is. All other paths will be prepended with the value of
- ``settings.MEDIA_URL``. For example, if the MEDIA_URL for your site was
- ``http://media.example.com/``::
- class CalendarWidget(forms.TextInput):
- class Media:
- css = {
- 'all': ('/css/pretty.css',),
- }
- js = ('animations.js', 'http://othersite.com/actions.js')
- >>> w = CalendarWidget()
- >>> print w.media
- <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://othersite.com/actions.js"></script>
- Media objects
- -------------
- When you interrogate the media attribute of a widget or form, the value that
- is returned is a ``forms.Media`` object. As we have already seen, the string
- representation of a Media object is the HTML required to include media
- in the ``<head>`` block of your HTML page.
- However, Media objects have some other interesting properties.
- Media subsets
- ~~~~~~~~~~~~~
- If you only want media of a particular type, you can use the subscript operator
- to filter out a medium of interest. For example::
- >>> w = CalendarWidget()
- >>> print w.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- >>> print w.media['css']
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- When you use the subscript operator, the value that is returned is a new
- Media object -- but one that only contains the media of interest.
- Combining media objects
- ~~~~~~~~~~~~~~~~~~~~~~~
- Media objects can also be added together. When two media objects are added,
- the resulting Media object contains the union of the media from both files::
- class CalendarWidget(forms.TextInput):
- class Media:
- css = {
- 'all': ('pretty.css',)
- }
- js = ('animations.js', 'actions.js')
- class OtherWidget(forms.TextInput):
- class Media:
- js = ('whizbang.js',)
- >>> w1 = CalendarWidget()
- >>> w2 = OtherWidget()
- >>> print w1.media + w2.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
- Media on Forms
- --------------
- Widgets aren't the only objects that can have media definitions -- forms
- can also define media. The rules for media definitions on forms are the
- same as the rules for widgets: declarations can be static or dynamic;
- path and inheritance rules for those declarations are exactly the same.
- Regardless of whether you define a media declaration, *all* Form objects
- have a media property. The default value for this property is the result
- of adding the media definitions for all widgets that are part of the form::
- class ContactForm(forms.Form):
- date = DateField(widget=CalendarWidget)
- name = CharField(max_length=40, widget=OtherWidget)
- >>> f = ContactForm()
- >>> f.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
- If you want to associate additional media with a form -- for example, CSS for form
- layout -- simply add a media declaration to the form::
- class ContactForm(forms.Form):
- date = DateField(widget=CalendarWidget)
- name = CharField(max_length=40, widget=OtherWidget)
- class Media:
- css = {
- 'all': ('layout.css',)
- }
- >>> f = ContactForm()
- >>> f.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
- Formsets
- ========
- A formset is a layer of abstraction to working with multiple forms on the same
- page. It can be best compared to a data grid. Let's say you have the following
- form::
- >>> from django import forms
- >>> class ArticleForm(forms.Form):
- ... title = forms.CharField()
- ... pub_date = forms.DateField()
- You might want to allow the user to create several articles at once. To create
- a formset out of an ``ArticleForm`` you would do::
- >>> from django.forms.formsets import formset_factory
- >>> ArticleFormSet = formset_factory(ArticleForm)
- You now have created a formset named ``ArticleFormSet``. The formset gives you
- the ability to iterate over the forms in the formset and display them as you
- would with a regular form::
- >>> formset = ArticleFormSet()
- >>> for form in formset.forms:
- ... print form.as_table()
- <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
- <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
- As you can see it only displayed one form. This is because by default the
- ``formset_factory`` defines one extra form. This can be controlled with the
- ``extra`` parameter::
- >>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
- Using initial data with a formset
- ---------------------------------
- Initial data is what drives the main usability of a formset. As shown above
- you can define the number of extra forms. What this means is that you are
- telling the formset how many additional forms to show in addition to the
- number of forms it generates from the initial data. Lets take a look at an
- example::
- >>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
- >>> formset = ArticleFormSet(initial=[
- ... {'title': u'Django is now open source',
- ... 'pub_date': datetime.date.today()},
- ... ])
- >>> for form in formset.forms:
- ... print form.as_table()
- <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
- <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr>
- <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
- <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
- <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
- <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
- There are now a total of three forms showing above. One for the initial data
- that was passed in and two extra forms. Also note that we are passing in a
- list of dictionaries as the initial data.
- Limiting the maximum number of forms
- ------------------------------------
- The ``max_num`` parameter to ``formset_factory`` gives you the ability to
- force the maximum number of forms the formset will display::
- >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
- >>> formset = ArticleFormset()
- >>> for form in formset.forms:
- ... print form.as_table()
- <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
- <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
- The default value of ``max_num`` is ``0`` which is the same as saying put no
- limit on the number forms displayed.
- Formset validation
- ------------------
- Validation with a formset is about identical to a regular ``Form``. There is
- an ``is_valid`` method on the formset to provide a convenient way to validate
- each form in the formset::
- >>> ArticleFormSet = formset_factory(ArticleForm)
- >>> formset = ArticleFormSet({})
- >>> formset.is_valid()
- True
- We passed in no data to the formset which is resulting in a valid form. The
- formset is smart enough to ignore extra forms that were not changed. If we
- attempt to provide an article, but fail to do so::
- >>> data = {
- ... 'form-TOTAL_FORMS': u'1',
- ... 'form-INITIAL_FORMS': u'1',
- ... 'form-0-title': u'Test',
- ... 'form-0-pub_date': u'',
- ... }
- >>> formset = ArticleFormSet(data)
- >>> formset.is_valid()
- False
- >>> formset.errors
- [{'pub_date': [u'This field is required.']}]
- As we can see the formset properly performed validation and gave us the
- expected errors.
- Understanding the ManagementForm
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- You may have noticed the additional data that was required in the formset's
- data above. This data is coming from the ``ManagementForm``. This form is
- dealt with internally to the formset. If you don't use it, it will result in
- an exception::
- >>> data = {
- ... 'form-0-title': u'Test',
- ... 'form-0-pub_date': u'',
- ... }
- >>> formset = ArticleFormSet(data)
- Traceback (most recent call last):
- ...
- django.forms.util.ValidationError: [u'ManagementForm data is missing or has been tampered with']
- It is used to keep track of how many form instances are being displayed. If
- you are adding new forms via JavaScript, you should increment the count fields
- in this form as well.
- Custom formset validation
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- A formset has a ``clean`` method similar to the one on a ``Form`` class. This
- is where you define your own validation that deals at the formset level::
- >>> from django.forms.formsets import BaseFormSet
- >>> class BaseArticleFormSet(BaseFormSet):
- ... def clean(self):
- ... raise forms.ValidationError, u'An error occured.'
- >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
- >>> formset = ArticleFormSet({})
- >>> formset.is_valid()
- False
- >>> formset.non_form_errors()
- [u'An error occured.']
- The formset ``clean`` method is called after all the ``Form.clean`` methods
- have been called. The errors will be found using the ``non_form_errors()``
- method on the formset.
- Dealing with ordering and deletion of forms
- -------------------------------------------
- Common use cases with a formset is dealing with ordering and deletion of the
- form instances. This has been dealt with for you. The ``formset_factory``
- provides two optional parameters ``can_order`` and ``can_delete`` that will do
- the extra work of adding the extra fields and providing simpler ways of
- getting to that data.
- ``can_order``
- ~~~~~~~~~~~~~
- Default: ``False``
- Lets create a formset with the ability to order::
- >>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
- >>> formset = ArticleFormSet(initial=[
- ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
- >>> for form in formset.forms:
- ... print form.as_table()
- <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
- <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
- <tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr>
- <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
- <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
- <tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr>
- <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
- <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
- <tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="text" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr>
- This adds an additional field to each form. This new field is named ``ORDER``
- and is an ``forms.IntegerField``. For the forms that came from the initial
- data it automatically assigned them a numeric value. Lets look at what will
- happen when the user changes these values::
- >>> data = {
- ... 'form-TOTAL_FORMS': u'3',
- ... 'form-INITIAL_FORMS': u'2',
- ... 'form-0-title': u'Article #1',
- ... 'form-0-pub_date': u'2008-05-10',
- ... 'form-0-ORDER': u'2',
- ... 'form-1-title': u'Article #2',
- ... 'form-1-pub_date': u'2008-05-11',
- ... 'form-1-ORDER': u'1',
- ... 'form-2-title': u'Article #3',
- ... 'form-2-pub_date': u'2008-05-01',
- ... 'form-2-ORDER': u'0',
- ... }
- >>> formset = ArticleFormSet(data, initial=[
- ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
- >>> formset.is_valid()
- True
- >>> for form in formset.ordered_forms:
- ... print form.cleaned_data
- {'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': u'Article #3'}
- {'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': u'Article #2'}
- {'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': u'Article #1'}
- ``can_delete``
- ~~~~~~~~~~~~~~
- Default: ``False``
- Lets create a formset with the ability to delete::
- >>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
- >>> formset = ArticleFormSet(initial=[
- ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
- >>> for form in formset.forms:
- .... print form.as_table()
- <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" />
- <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
- <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
- <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr>
- <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
- <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
- <tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr>
- <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
- <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
- <tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr>
- Similar to ``can_order`` this adds a new field to each form named ``DELETE``
- and is a ``forms.BooleanField``. When data comes through marking any of the
- delete fields you can access them with ``deleted_forms``::
- >>> data = {
- ... 'form-TOTAL_FORMS': u'3',
- ... 'form-INITIAL_FORMS': u'2',
- ... 'form-0-title': u'Article #1',
- ... 'form-0-pub_date': u'2008-05-10',
- ... 'form-0-DELETE': u'on',
- ... 'form-1-title': u'Article #2',
- ... 'form-1-pub_date': u'2008-05-11',
- ... 'form-1-DELETE': u'',
- ... 'form-2-title': u'',
- ... 'form-2-pub_date': u'',
- ... 'form-2-DELETE': u'',
- ... }
- >>> formset = ArticleFormSet(data, initial=[
- ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
- >>> [form.cleaned_data for form in formset.deleted_forms]
- [{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': u'Article #1'}]
- Adding additional fields to a formset
- -------------------------------------
- If you need to add additional fields to the formset this can be easily
- accomplished. The formset base class provides an ``add_fields`` method. You
- can simply override this method to add your own fields or even redefine the
- default fields/attributes of the order and deletion fields::
- >>> class BaseArticleFormSet(BaseFormSet):
- ... def add_fields(self, form, index):
- ... super(BaseArticleFormSet, self).add_fields(form, index)
- ... form.fields["my_field"] = forms.CharField()
- >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
- >>> formset = ArticleFormSet()
- >>> for form in formset.forms:
- ... print form.as_table()
- <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
- <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
- <tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr>
- Using a formset in views and templates
- --------------------------------------
- Using a formset inside a view is as easy as using a regular ``Form`` class.
- The only thing you will want to be aware of is making sure to use the
- management form inside the template. Lets look at a sample view::
- def manage_articles(request):
- ArticleFormSet = formset_factory(ArticleForm)
- if request.method == 'POST':
- formset = ArticleFormSet(request.POST, request.FILES)
- if formset.is_valid():
- # do something with the formset.cleaned_data
- else:
- formset = ArticleFormSet()
- return render_to_response('manage_articles.html', {'formset': formset})
- The ``manage_articles.html`` template might look like this::
- <form method="POST" action="">
- {{ formset.management_form }}
- <table>
- {% for form in formset.forms %}
- {{ form }}
- {% endfor %}
- </table>
- </form>
- However the above can be slightly shortcutted and let the formset itself deal
- with the management form::
- <form method="POST" action="">
- <table>
- {{ formset }}
- </table>
- </form>
- The above ends up calling the ``as_table`` method on the formset class.
|