pax_global_header00006660000000000000000000000064122106674550014522gustar00rootroot0000000000000052 comment=773b24eb0ad8c2f35af3d829e07fa25bffea87c9 django-crispy-forms-1.4.0/000077500000000000000000000000001221066745500154215ustar00rootroot00000000000000django-crispy-forms-1.4.0/.gitignore000066400000000000000000000004141221066745500174100ustar00rootroot00000000000000setuptools_git-0.3.4-py2.6.egg #buildout's specific .installed.cfg eggs/* bin/* build/* dist/* develop-eggs/* parts/* downloads/* #egg's specific *.egg-info #defaults *.pyc *.pyo __pycache__ #temp file tempfile *.swp # coverage .coverage _build # OSX *.DS_Store django-crispy-forms-1.4.0/.travis.yml000066400000000000000000000006301221066745500175310ustar00rootroot00000000000000language: python python: - "2.6" - "2.7" - "3.3" env: - DJANGO=1.3.7 - DJANGO=1.4.5 - DJANGO=1.5.1 install: - pip install Django==$DJANGO - pip install "file://`pwd`#egg=django-crispy-forms[tests]" - pip install -e . --use-mirrors script: - make test notifications: email: false matrix: exclude: - python: "3.3" env: DJANGO=1.4.5 - python: "3.3" env: DJANGO=1.3.7 django-crispy-forms-1.4.0/CHANGELOG.md000066400000000000000000000604411221066745500172370ustar00rootroot00000000000000# CHANGELOG for django-crispy-forms ## 1.4.0 Special thanks in this release to **James Friedman @jamesmfriedman**, for his amazing support in PR #213, adding initial Bootstrap 3 support. * Bootstrap 3 inline forms support and docs for inline forms with Bootstrap 3, see #233. * `update_attributes` can now work with a field name, see docs. * Adjusted unicode checkings for Python 3, see #231. * Adjusted how bootstrap `Tab` layout object attributes are applied to make sense, see #228. * Major refactor of testing suite architecture, breaking huge `tests.py` file into several and also splitting tests for different template packs into different tests cases, runners for template packs updated. * Added support for horizontal forms in bootstrap3, see #209. * Fixed spaces missing when rendering several submit inputs continued, see #211. * Fixed checkboxes and radios for Bootstrap3, adjusted multiple inline radios and checkboxes, see #225. * Update accordion markup for bootstrap3 compatibilty, see #229. * Moved `UneditableField` to bootstrap module, place where it should live, no backwards compatible import left behind. * Added `bootstrap3` template pack thanks to James Friedman, see #213 and #209. * `RadioSelect` and `CheckboxSelectMultiple` widget values and texts were being localized, when they shouldn't bee, see #214. * If Django widget attrs where set for `RadioSelect` or `CheckboxSelectMultiple` they were not being rendered by crispy-forms, see #206. * `form_show_labels` wasn't working correctly with some layout objects, see #193. ## 1.3.2 (2013/6/23) * Labels were not being rendered with `|crispy` filter, see #202. ## 1.3.1 (2013/6/17) * Fix default value for `form_show_labels` in case FormHelper doesn't define it, see #199. * Added a backported version of `override_settings` for testing django 1.3.7 and adding it to Travis-ci matrix. ## 1.3.0 (2013/6/16) Special thanks in this release to **Charlie Denton @meshy**, for his amazing support in PRs #189 and #190, long due. * Deprecated `Tab` and `TabHolder` imports from `layout.py` module, they now live in `bootstrap.py` module. * Removed Python 2.5 compatibility. * Added `disable_csrf` helper attribute, see docs. * Travis-ci support thanks to Charlie Denton, see #190. * Python 3 compatibility thanks to Charlie Denton, see #189 and #190. * Added a settings variable named `CRISPY_ALLOWED_TEMPLATE_PACKS` for adding easily support for new template packs, see #192. * Added `{% crispy_addon %}` tag, see #195. * Make `CRISPY_TEMPLATE_PACK` optional for tests * Make tests run the same exacty way with `runtests.py` and `manage.py test`, see #183. * Bug fix for `wrap_together` when using it with partial slices. * Fixes for `KeepContext` context manager, see #180. * Added `FormHelper.field_template` attribute, for easily override field template for a specific form/formset, see docs. * Added a template for rendering formsets inline within tables named `bootstrap/table_inline_formset.html`, that can be easily used in conjunction with `FormHelper.template`. * Added `FormHelper.template` attribute, that easily allows to override form/formset general structure template, see docs. * Added `form_show_labels` helper attribute. * Redoing filters to use `isinstance` instead of hacky internal name checking, this way subclasses of standard fields will work out of the box with crispy-forms, see #176. ## 1.2.8 (2013/5/10) * Bug fix for `KeepContext` context manager, when crispy-forms used with Jingo/Jinja2 templates, see #179. * Some formset tests were breaking in some Django versions. Also added a `make test` for easily running project tests, see #178. ## 1.2.7 (2013/5/6) * Bug fix for model formsets and inline formsets, when being rendered with a `FormHelper` with a layout set, where some hidden formset management fields would be missing, breaking saving to database. * Added `render_hidden_fields` attribute to `FormHelper`, see docs. * Added `render_hidden_fields` attribute to `FormHelper`, see docs. ## 1.2.6 (2013/5/1) * Fixes to `Container` and `TabHolder`, affecting class variable helpers with layouts containing `TabHolder` or `AccordionGroup` objects, see #172. * Bug fix for `KeepContext` context manager, see #172. ## 1.2.5 (2013/4/25) * Avoid raising Exceptions in `|as_crispy_field` filter when not in DEBUG mode. * Popping `css_id` to avoid having a css-id attribute, see #167. * Fixed a bug in dynamic layout API, when wrapping layout objects that had arguments passed after fields. Moving `LayoutSlice` to `layout_slice` module. * Fixed test failing when tests runned from manage.py test. * Fixed testing name conflict, see #130. ## 1.2.4 (2013/4/13) * Added `wrapper_class` kwarg to `Field` layout object, see #163. * Added `Accordion` and `AccordionGroup` bootstrap layout objects, see #162. * Bug fix in `render_crispy_form` to avoid override existing context, see #153. * Use formset iterator instead of `forms` list attribute, see #152. * Don't display fieldset legend if empty, see #147 and #155. * Bug fix for pickling crispy forms by powderflask, see #107. * Switched from `django.form.utils.flatatt` to internal `flatatt` utils implementation, this allows adding data-attrs to `FormActions` and `StrictButton`. * `render_field` now uses a context manager to avoid side effects when layout objects update template context. This makes context mutability safe within layout objects. * Added `greedy` kwarg to `filter` dynamic API. * Fixing error logging on `|as_crispy_field` filter, see #135. * Implemented `__delitem__`, `__len__` and `__setitem__` in `LayoutObject` and `DynamicLayoutHandler`, this avoids pylint warnings, see #114. * Docs folder no longer included when installing crispy-forms, see #132. * Added `wrap_once`, `update_attributes`, `map` and `pre_map` to LayoutSlice. ## 1.2.3 (2012/12/4) * Fixed imports to be relative to package, avoiding namespace collisions. * Removed circular dependency between `layout` and `bootstrap`, see #129. * Bug fix, adapted use of inspect module in `utils.py` to avoid breaking Python 2.5 compatibility. ## 1.2.2 (2012/11/30) * Bug fix, reduction of white space in crispy-forms output could mess within tags, see #127, reverting part of this reduction. * Renamed `AppendedPrependedText` to `PrependedAppendedText`. * Moved `Tab` and `TabHolder` to `bootstrap.py`. ## 1.2.1 (2012/11/28) * Bug fix `help_text_inline` set to True, see #117. * New fix for the space between buttons problems, see #62. * Reduced importantly whitespace in html generated by crispy-forms, forms are now more compact. * Added support for specifying a template pack per form, see #66 and #109. * Removed `clearfix` class from bootstrap templates, not necessary anymore, see #105. * Space cleanup in bootstrap templates, thanks to Si Feng, see #122. * Fixed `MultiField` to work with `form_show_errors` helper attribute. * Fixed a bug in `MultiField` that set error class when there were form errors, no matter if the fields with errors were contained within, see #120. * `FieldWithButtons` now supports `Field` layout object as its first parameter, for setting input attributes. * Bug fixes for `FieldWithButtons`, field label, `help_text` or error messages were not being rendered, see #121. * Fixed a bug that was making crispy-forms render extra fields with ModelForms that didn't have `Meta.fields` defined, thanks to Jean-Baptiste Juin for reporting it. * Fixed a bug that was breaking Django 1.2 compatibility when copying context variables, thanks to Alex Yakovlev for submitting a patch, see #108. * Fixed a bug for `AppendedText`, `PrependedText` and `AppendedPrependedText` layout objects, thanks to Bojan Mihelac, see #104. * Fixed a bug in appended and prepended text layout objects for respecting hidden fields, thanks to Bojan Mihelac, see #103. * Added two new bootstrap layout objects: `FieldWithButtons` and `StrictButton`. * Added checks and better error messages for dynamic API. * Fixed `get_layout_objects` recursive call for Python2.5 compatibility, thanks to Can Başçıl for reporting it. ## 1.2.0 (2012/9/24) * Update prepended and appended templates to respect hidden fields, thanks to Bojan Mihelac, see #GH-103. * Added `InlineCheckboxes` to bootstrap layout objects, for rendering checkboxes inline. * `BaseInput` subclasses, like `Submit` can now have its value set to a context variable. * Rendering inputs added with `add_input` in bootstrap using the right templates, see #GH-95. * Improved formsets rendering docs thanks to Samuel Goldszmidt, see #GH-92. * Added `Tab` and `TabHolder` layout objects thanks to david-e, see #GH-91. * Fixed default bootstrap button default classes thanks to david-e, see #GH-90. * Fixed some flaws in new testing structure by Markus Hametner. * Added helper attribute `error_text_inline` thanks to Lee Semel for controlling how to render form errors, as a block or inline, see #GH-87. * Support `ModelMultipleChoiceField` on `checkboxselectmultiple`, see #GH-86. * Redoing testing structure a litte bit, to run uni_form and bootstrap tests separately. They share most of the code base, but templates pack are separate and we need to care both have the same quality assurance. * `AppendedText`, `PrependedText` and `AppendedPrependedText` were not respecting `form_show_errors` helper attribute, see #GH-77. * Added a version string to the app under root __init__, see #GH-76. * Added `html5_required` helper attribute for rendering required fields using HTML5 required attribute within the input, see #GH-72. Thanks to Lloyd Philbrook. * Some docs typos and errors fixed, also a major upgrade to docs covering the new functionality. * Adding a `utils.render_crispy_form` function, that renders a form the crispy way in Python code. This might be useful with AJAX, testing or text generation/manipulation, see #GH-64. * Tiny cosmetic fix, that adds an space after a button, see #GH-62. * `MultiField` and `Fieldset` layout objects can now have any kind of attribute defined, thanks to Lloyd Philbrook, see #GH-71. * Making `Fieldset`, `MultiField` & `HTML` contents lazy translatable thanks to Rivo Laks, see #GH-69. * Fixing `radioselect` checked status when used for a FK in a ModelForm, see #GH-68. * Fixing `form.Meta` usage, using instance `fields` instead of static `Meta` definition, so that it works when updating forms on the go, see #GH-59. * Added a low level manipulation API for layout and layout objects. Added a `LayoutObject` base class that creates an interface. This allows to access nested fields easily and use list methods without know internals of the system. * Added a `|classes` filter that returns field's classes. * Now `FormHelper` can accept a form instance as an optional first argument, from which it can build a default layout. * Added an API for manipulating dynamic layouts and programmatic layout building. * Added `UneditableField` bootstrap layout object for uneditable fields. * Support for hiding fields using `Field('field_name', type="hidden")`, see #GH-55. * Avoid template context pollution of variable `form` after using {% crispy %} tag, see #GH-54. * Added an `attrs` helper attribute, for more flexible form attributes, see #GH-48. * New `AppendedPrependedText` layout object thanks to Samuel Goldszmidt, see #GH-45. * Removal of some whitespace in crispy form's HTML generated, see #GH-42. * New `MultiWidgetField` layout object by Michal Kuffa, see #GH-39. ## 1.1.4 (2012/5/24) * Multithread safety improvements for `BasicNode`. * Security fix: Thread safety fixes to `CrispyFieldNode` thanks to Paul Oswald. This avoids leaking information between requests in multithreaded WSGI servers. * Added css class `control-label` to `AppendedText` and `PrependedText` layout object's templates. * `{% crispy field %}` tag can now pass attrs to `MultiWidget` subclasses by Michal Kuffa. `attrs` are set for sub-widgets. Also `attrs` can now be an iterable for passing different attributes to different sub-widgets. For example,this way MultiWidget's widgets get css classes set correctly. * Turning underscores into hyphens for `Field` layout objects. * Fix for `ChoiceFields` using non-string choices with radio buttons thanks to Rudy Mutter. See #GH-46, #GH-43 and #GH-35. ## 1.1.3 (2012/4/21) * `|crispy` and `|as_crispy_field` filters were not rendering errors. Thanks to @ximi for reporting it and submitting a patch. See issue #GH-28. * Fixing a test that was breaking when language was not English. Thanks to @gaftech, see #GH-30. * Fixing `radioselect.html` and `checkboxselectmultiple.html` templates. Thanks to Christopher Petrilli for submitting a patch for `radioselect`. See issue #GH-35. * HTML attributes can now be set in `BaseInput` subclasses like `Button` by @jamesmfriedman. See #GH-32. * Fix for dynamic crispy-forms with Meta classes by Jeroen Vloothuis. See #GH-37. * Labels now use `id_for_label` instead of `auto_id` to avoid ids breaking on multiwidgets. by Daniel Izquierdo. See #GH-38. * Adding a flatatt custom function in `utils.py` for flatting extra HTML attributes. * HTML attributes can now be set in `Div` layout object. * Adding tests for new functionality and bugs. ## 1.1.2 (2012/2/29) * input name attribute is no longer slugified if only one word is provided, respecting caps. * Changes in bootstrap global error templates by David Bennett. * Added class `control-label` to labels, for horizontal layout thanks to bitrut. * Using `{{ field.html_name }}` instead of `{{ field.name }}` in field templates, so that they work with form prefixes (formwizard) by Patrick Toal. * Fixing error rendering in bootstrap AppendedText and PrependedText. * Applying `field.css_classes` in bootstrap `field.html` instead of widget classes. * Fixes for bootstrap simple checkbox input to be wrapped correctly. ## 1.1.1 (2012/2/17) * Fixing a critical bug in bootstrap templates, that was breaking `{% load crispy_forms_tags %}` ## 1.1.0 * Fixing produced html by a checkbox field, closing label the right way and rendering checkbox in the right place. * Passing full context to field rendering, to be consistent and having acess in `field.html` template to helper attributes. * Custom helper attributes can now be set and will be part of templates context, this way you can define custom specific behavior. * Adding @kennethlove bootstrap template pack into django-crispy-forms core. * Adding `CRISPY_TEMPLATE_PACK` setting variable to easily switch between different template packs. Default template pack is now bootstrap. * Upgrading bootstrap templates, fixing some bugs and redoing the hierarchy. * Upgrading tests for multiple template packs. * Renaming `UNIFORM_FAIL_SILENTLY` setting variable to `CRISPY_FAIL_SILENTLY`, upgrading migration instructions. * Redoing bootstrap `field.html` template to render `radioselect` and `checkboxselectmultiple` Django widgets a la bootstrap. * Adding a `render_unmentioned_fields` helper attribute, that renders all fields in a form, no matter what the layout is. Default is `False`. * Adding a `|css_class` filter that renders field classes in an elegant way. * Turning `|with_class` filter into `{% crispy_field %}` tag, so that parameters for rendering the field can be passed. * Adding a `help_text_inline` helper attribute, that controls wether to render help texts in bootstrap with "help-inline" or "help-block". * Adding a `flat_attrs` variable to the context passed to `field.html` to be able to do all kind of html attributes when rendering a field, using `Field` layout object. * Adding a `template` kwarg to `Field` layout object that allows to override template used for rendering a field. * Adding a `bootstrap.py` module that holds bootstrap specific layout objects, for higher bootstrap integration. * Adding a `AppendedText`, `PrependedText` and `FormActions` bootstrap layout objects. First two based in polyvalent `Field` layout object. ## 1.0.0 * Using `baseinput.html` template within `whole_uni_form.html`, to be DRY and consistent. * `BaseInput` subclasses like `Submit` can now have ids set, ussing `css_id` * Adding a simplified alternative syntax for `{% uni_form %}` tag. We can now do `{% uni_form form %}` for rendering a form using a helper, instead of `{% uni_form form form.helper %}`, if the `FormHelper` attribute attached to the form is named `helper`. * Improving `rendered_fields` checking performance. * Layouts are now rendered strictly. We don't render fields missed in the layout. If the form has a Meta class with `fields` or `exclude`, then we follow Django standards. * Added `Field` layout object. You can wrap name fields within and set all kind of attributes easily or override widget template. * Fixed #GH-111 we were not rendering all the classes in `|with_class` filter * Moving django-uni-form to django-crispy-forms. Renaming tags, filters and modules. Updating tests and so on. Adding migration instructions. * More work on simpler and easier docs. * Adding `form_show_errors` helper attribute, that controls wether to render or not `form.errors` * Improving template hierarchy for more template code reusability. # CHANGELOG for django-uni-form ## 0.9.0 You can read on how to use new features included in this version at: http://tothinkornottothink.com/post/10398684502/django-uni-form-0-9-0-is-out-security-fix * Fixed a bug in `|with_class` filter so that it supports `show_hidden_initial`, see #GH-95 to not break. * Fixed a problem on Fieldset's legends internationalization. Thanks to Bojan Mihelac, see #GH-90. * Fixed XSS bug thanks to Charlie Denton, see #GH-98. Errors cannot be rendered safe, because field's input can be part of the error message, that would mean XSS. * Updating and improving docs, adding more use case examples. * Split `helpers.py` file into `helper.py`, `layout.py` and `utils.py`. Added a deprecation warning. * Improved testing coverage, specially for formsets and i18n. * Improved rendering performance of `{% uni_form %}` tag and `|as_uni_form` filter avoiding reloading templates every time, see #GH-81. * Added support for Django `Form.error_css_class` and `Form.required_css_class` custom CSS classes, see #GH-87. * Moved template code in Layout objects into separate files in `uni_form/layout` directory. Layout objects templates can now be easily overriden, see #GH-37. * `form_style` can now be used without having to set a helper Layout, see #GH-85. * `form_action` is not lowered anymore and `form_action` is set to "" by default instead of "." thanks to Jianbo Guo, see #GH-84. * `Multifield` field template `multifield.html` markup fixed, adding `help_text` support and removing `labelclass` from labels. * Fixed testing suite, when run not using `DjangoTestSuiteRunner` provided, thanks to Narsil #GH-82. * Removed test_project from the project. * Improved `MultiField` performance avoiding instantiating BoundFields twice. * Fixed a bug in `MultiField` that raised an exception when internal fields had errors, because of `self.css` not existing. * Added an extra optional parameter to `render_field` called `layout_object`, used for storing in it a list of bound fields. * Refactor all Layout objects to use templates and not having hardcoded HTML in the code, based on Jonas Obrist work. Resolves Issue #GH-37 * Added a Layout object called `Div`. `Row` and `Column` both inherit from `Div` * `Layout` can now be a child of `Layout`, see issue #GH-76. ## 0.8.0 You can read on how to use new features included in this version at: http://tothinkornottothink.com/post/7339670508/new-kung-fu-in-django-uni-form-0-8-0 * Elevated Miguel Araujo to project lead! * Added a forloop simulator for formset forms rendering. * `ButtonHolder` Layout object added for holding `HTML` and buttons: `Submit`, `Reset`, `Button`. * Turned BaseInput inherited objects like: `Submit`, `Reset`, `Hidden` and `Button` into Layout objects. * Fixed a bug with `rendered_fields` when no fields where in the Layout. * `Fieldset` legends are now templates full context aware. * Based on @issackelly's and @johnthedebs's work a template called `betterform` has been added for supporting @carljm's form-utils BetterForms. * `FormHelper` method `get_attr` has been renamed to `get_attributes` * `uni_form_tags` has been split into two different files: `uni_form_tags` and `uni_form_filters`. * Removing i18n tags from the templates, as they are not necessary anymore. * Removed all the internationalized hardcoded text, in favor of template variables: `form_error_title` and `formset_error_title`, both can be set as helper's attributes. * `as_uni_errors` filter can now render formset's `non_form_errors` uni-form way. * Moved `{% uni_form_setup %}` tag to use STATIC_URL instead of MEDIA_URL * Added the possibility to specify a helper for formsets too. * Renamed media directory to static, to be compatible with Django 1.3 staticfiles. * Added a `form_style` FormHelper attribute for setting global style of a form: inline or default. * Turning `HTML` into a full context aware django template field, having access to the whole context of the template in which the form is rendered. * Turning `Layout` and `Fieldset` fields attributes into lists, so that they can be changed dynamically. * Changing formHints from paragraphs to divs, so ul or ol can be placed within. * Removing slugify filter from form ids, so they can be set as user's preferences. * Added CSS class 'asteriskField' for asterisks. Added CSS class 'fieldRequired' for required input labels. * `UNIFORM_FAIL_SILENTLY` variable setting has been added for making django-uni-form log errors and fail silently, based on Adam Cupiał's work. * Several bug fixes in `MultiField`. * Added unicode support for layout field names and improved error handling. * Refactored testing system and raised testing coverage. * Clean part of the code base and comments. All old CSRF code for supporting old versions of Django has been removed. * Refactored BasicNode for better readability and reducing lines of code. * Added formsets support based on Victor Nagy's (nagyv) and Antti Kaihola's (akahiola) work. * Bug fix in `{% uni_form %}` tag that didn't work without a helper and it was meant to be optional. * CSS classes can be set in Submit buttons. * Thanks to J. Javier Maestro (jjmaestro) now we can set ids and classes for `Fieldset`, `MultiField`, `Row` and `Column`. * Thanks to Richard Marko (sorki) changed CSS class of PasswordInput widget. * Removing `Toggle` class as it wasn't being used anywhere. * Moved `BaseInput` to helpers and removed `util.py` file. * Removed `{% uni_form_jquery %}` tag * Removed `namify` function from tags, as It wasn't being used anywhere. * Improved internal documentation * form methods generated by FormHelper are in lowercase (http://github.com/pydanny/django-uni-form/issues#issue/20) * Thanks to Nagy Viktor added form_tag attribute to FormHelper. Now you can use the uni_form tag without the leading and trailing form tags. * Thanks for Alison Rowland for giving django-uni-form sphinx docs * Incorporated uni-form 1.4 by Dragan Babic * Provide better adherence to uni-form specification of error messages * mirumee provided some great work for making FormHelper more subclassable. * django-uni-form 0.8 and higher lays out the HTML for the uni_form tag differently. The errorMsg div is now outside the fieldset as it should be. * Thanks to Casper S. Jensen django-uni-form now supports 1.2 style csrf_token. * csrf_token does not break earlier versions of Django. This will change when no version of django does not support csrf_token. * Thanks to j0hnsmith changed {{ error }} to {{ error|safe }} so that html (eg links) can be added to error messages. * Thanks to j0hnsmith changed {{ field.label }} to {{ field.label|safe }} so that html (eg links) can be added to field labels * Kudos to Stepan Rakhimov fixed an admin datetime issue. * Thanks to patrys (Patryk Zawadzki) FormHelper class is now easily subclass-able. * Sorki (Richard Marko) made it so things work better in direct_to_template. ## 0.7.0 * Removed a
from the layout module. * Changed templatetags/uni_form.py to templatetags/uni_form_tags.py. Yes, this breaks backwards compatibility but fixes a namespace problems in Django with naming a templatetag library after the parent application. * Changed form_action attribute to accept not just named URLs but also any old URL. * Added in uni_form_setup tag. * Added tests * Added several new contributors including Dragan Babic * Added Danish language translation django-crispy-forms-1.4.0/CONTRIBUTORS.txt000066400000000000000000000042141221066745500201200ustar00rootroot00000000000000============ Contributors ============ django-crispy-forms Project Lead ================================ * Miguel Araujo django-uni-form Project Founder =============================== * Daniel Greenfeld Contributors ============ * Alison Rowland * Bojan Mihelac * bjunix * Casper S. Jensen * Chris Adams * Eddy Mulyono * j0hnsmith * James Pic * James Tauber * Karl Bowden * Marcin Grzybowski * Michael Lind Mortensen * mirumee * mvaerle * Nagy Viktor * Patrick Lauber * Patryk Zawadzki * Skylar Saveland * Stepan Rakhimov * John Maxwell * Richard Marko * Victor Nagy * Antti Kaihola * J. Javier Maestro * Issac Kelly * John Debs * Adam Cupiał * Nicolas Patry * Jonas Obrist * Charlie Denton * Jason Culverhouse * James Turnbull * Patrick Toal * David Bennett * bitrut * ximi * Christopher Petrilli * James Friedman * Jeroen Vloothuis * Daniel Izquierdo * gaftech * Michal Kuffa * Paul Oswald * Rudy Mutter * Samuel Goldszmidt * Andrei Antoukh * * Rivo Laks * Lloyd Philbrook * Piet Delport * * Markus Hametner * Thomas Grainger * Lee Semel * * Alex Yakovlev * Si Feng * Igor Katson * Ben Delevingne * * Evan Borgstrom * Daniel Shapiro * * Stefan "hr" Berder (白峰) * Suleyman Melikoglu * Vladislav Mitov * Nemesis Fixx * Chris Vigelius * David Cramer * Stas Rudakou * * Svyatoslav Bulbakha * Andres Vargas * Gabe Jackson * Camilo Nova * * Daniel Mascarenhas django-crispy-forms-1.4.0/LICENSE.txt000066400000000000000000000020671221066745500172510ustar00rootroot00000000000000Copyright (c) 2009-2011 Miguel Araujo and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.django-crispy-forms-1.4.0/MANIFEST.in000066400000000000000000000003161221066745500171570ustar00rootroot00000000000000include CONTRIBUTORS.txt include LICENSE.txt include MANIFEST.in include README.rst recursive-include crispy_forms/static * recursive-include crispy_forms/templates * recursive-include crispy_forms/tests * django-crispy-forms-1.4.0/Makefile000066400000000000000000000002731221066745500170630ustar00rootroot00000000000000.PHONY: develop test develop: pip install -q "file://`pwd`#egg=django-crispy-forms[tests]" pip install -q -e . --use-mirrors test: develop cd crispy_forms/tests && python runtests.pydjango-crispy-forms-1.4.0/README.rst000066400000000000000000000063641221066745500171210ustar00rootroot00000000000000=================== django-crispy-forms =================== .. image:: https://travis-ci.org/maraujop/django-crispy-forms.png?branch=master :alt: Build Status :target: https://travis-ci.org/maraujop/django-crispy-forms The best way to have Django_ DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered HTML without writing HTML in templates. All this without breaking the standard way of doing things in Django, so it plays nice with any other form application. The application mainly provides: * A filter named ``|crispy`` that will render elegant div based forms. Think of it as the built-in methods: ``as_table``, ``as_ul`` and ``as_p``. You cannot tune up the output, but it is easy to start using it. * A tag named ``{% crispy %}`` that will render a form based on your configuration and specific layout setup. This gives you amazing power without much hassle, helping you save tons of time. Django-crispy-forms supports several frontend frameworks, such as Twitter `Bootstrap`_ (versions 2 and 3), `Uni-form`_ and Foundation. You can also easily adapt your custom company's one, creating your own, `see the docs`_ for more information. You can easily switch among them using ``CRISPY_TEMPLATE_PACK`` setting variable. .. _`Uni-form`: http://sprawsm.com/uni-form .. _`Bootstrap`: http://twitter.github.com/bootstrap/index.html .. _`see the docs`: http://django-crispy-forms.rtfd.org Authors ======= django-crispy-forms is the new django-uni-form. django-uni-form was an application created by `Daniel Greenfeld`_ that I leaded since version 0.8.0. The name change tries to better explain the purpose of the application, which changed in a significant way since its birth. If you are upgrading from django-uni-form, we have `instructions`_ for helping you. * Lead developer: `Miguel Araujo`_ .. _`Daniel Greenfeld`: https://github.com/pydanny .. _`Miguel Araujo`: https://github.com/maraujop .. _`instructions`: http://django-crispy-forms.readthedocs.org/en/1.1.1/migration.html Example ======= This is a teaser of what you can do with latest django-crispy-forms. `Find here the gist`_ for generating this form: .. image:: http://i.imgur.com/LSREg.png .. _`Find here the gist`: https://gist.github.com/1838193 Documentation ============= For extensive documentation see the ``docs`` folder or `read it on readthedocs`_ .. _`read it on readthedocs`: http://django-crispy-forms.readthedocs.org/en/latest/index.html Special thanks ============== * To Daniel Greenfeld (`@pydanny`_) for his support, time and the opportunity given to me to do this. * The name of the project was suggested by the fantastic Audrey Roy (`@audreyr`_) * To Kenneth Love (`@kennethlove`_) for creating django-uni-form-contrib from which bootstrap template pack was started. .. _`@audreyr`: https://github.com/audreyr .. _`@pydanny`: https://github.com/pydanny .. _`@kennethlove`: https://github.com/kennethlove Note ---- django-crispy-forms supports Django 1.3 or higher with Python 2.6.x, Python 2.7.x and Python 3.3.x. If you need to support Python 2.5 or Django 1.2 you will need to use a version of django-crispy-forms less than 1.3. For earlier versions of Django or Python you will need to use django-uni-form 0.7.0. .. _Django: http://djangoproject.com django-crispy-forms-1.4.0/__init__.py000066400000000000000000000000001221066745500175200ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/000077500000000000000000000000001221066745500201405ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/LICENSE000066400000000000000000000020651221066745500211500ustar00rootroot00000000000000Copyright (c) 2009 Daniel Greenfeld and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.django-crispy-forms-1.4.0/crispy_forms/__init__.py000066400000000000000000000000571221066745500222530ustar00rootroot00000000000000# -*- coding: utf-8 -*- __version__ = '1.4.0' django-crispy-forms-1.4.0/crispy_forms/base.py000066400000000000000000000025101221066745500214220ustar00rootroot00000000000000# -*- coding: utf-8 -*- def from_iterable(iterables): """ Backport of `itertools.chain.from_iterable` compatible with Python 2.5 """ for it in iterables: for element in it: if isinstance(element, dict): for key in element: yield key else: yield element class KeepContext(object): """ Context manager that receives a `django.template.Context` instance, tracks its changes and rolls them back when exiting the context manager, leaving the context unchanged. Layout objects can introduce context variables, that may cause side effects in later layout objects. This avoids that situation, without copying context every time. """ def __init__(self, context): self.context = context def __enter__(self): self.old_set_keys = set(from_iterable(self.context.dicts)) def __exit__(self, type, value, traceback): current_set_keys = set(from_iterable(self.context.dicts)) diff_keys = current_set_keys - self.old_set_keys # We remove added keys for rolling back changes for key in diff_keys: self._delete_key_from_context(key) def _delete_key_from_context(self, key): for d in self.context.dicts: if key in d: del d[key] django-crispy-forms-1.4.0/crispy_forms/bootstrap.py000066400000000000000000000273111221066745500225330ustar00rootroot00000000000000import warnings from random import randint from django.template import Context, Template from django.template.loader import render_to_string from django.template.defaultfilters import slugify from .compatibility import text_type from .layout import LayoutObject, Field, Div from .utils import render_field, flatatt, TEMPLATE_PACK class PrependedAppendedText(Field): template = "%s/layout/prepended_appended_text.html" % TEMPLATE_PACK def __init__(self, field, prepended_text=None, appended_text=None, *args, **kwargs): self.field = field self.appended_text = appended_text self.prepended_text = prepended_text if 'active' in kwargs: self.active = kwargs.pop('active') self.input_size = None css_class = kwargs.get('css_class', '') if css_class.find('input-lg') != -1: self.input_size = 'input-lg' if css_class.find('input-sm') != -1: self.input_size = 'input-sm' super(PrependedAppendedText, self).__init__(field, *args, **kwargs) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): context.update({'crispy_appended_text': self.appended_text, 'crispy_prepended_text': self.prepended_text, 'input_size' : self.input_size, 'active': getattr(self, "active", False)}) return render_field(self.field, form, form_style, context, template=self.template, attrs=self.attrs, template_pack=template_pack) class AppendedPrependedText(PrependedAppendedText): def __init__(self, *args, **kwargs): warnings.warn("AppendedPrependedText has been renamed to PrependedAppendedText, \ it will be removed in 1.3.0", PendingDeprecationWarning) super(AppendedPrependedText, self).__init__(*args, **kwargs) class AppendedText(PrependedAppendedText): def __init__(self, field, text, *args, **kwargs): kwargs.pop('appended_text', None) kwargs.pop('prepended_text', None) self.text = text super(AppendedText, self).__init__(field, appended_text=text, **kwargs) class PrependedText(PrependedAppendedText): def __init__(self, field, text, *args, **kwargs): kwargs.pop('appended_text', None) kwargs.pop('prepended_text', None) self.text = text super(PrependedText, self).__init__(field, prepended_text=text, **kwargs) class FormActions(LayoutObject): """ Bootstrap layout object. It wraps fields in a
Example:: FormActions( HTML(Information Saved), Submit('Save', 'Save', css_class='btn-primary') ) """ template = "%s/layout/formactions.html" % TEMPLATE_PACK def __init__(self, *fields, **kwargs): self.fields = list(fields) self.template = kwargs.pop('template', self.template) self.attrs = kwargs if 'css_class' in self.attrs: self.attrs['class'] = self.attrs.pop('css_class') def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): html = u'' for field in self.fields: html += render_field(field, form, form_style, context, template_pack=template_pack) return render_to_string(self.template, Context({'formactions': self, 'fields_output': html})) def flat_attrs(self): return flatatt(self.attrs) class InlineCheckboxes(Field): """ Layout object for rendering checkboxes inline:: InlineCheckboxes('field_name') """ template = "%s/layout/checkboxselectmultiple_inline.html" % TEMPLATE_PACK def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): context.update({'inline_class': 'inline'}) return super(InlineCheckboxes, self).render(form, form_style, context) class InlineRadios(Field): """ Layout object for rendering radiobuttons inline:: InlineRadios('field_name') """ template = "%s/layout/radioselect_inline.html" % TEMPLATE_PACK def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): context.update({'inline_class': 'inline'}) return super(InlineRadios, self).render(form, form_style, context) class FieldWithButtons(Div): template = '%s/layout/field_with_buttons.html' % TEMPLATE_PACK def render(self, form, form_style, context): # We first render the buttons buttons = '' for field in self.fields[1:]: buttons += render_field( field, form, form_style, context, '%s/layout/field.html' % TEMPLATE_PACK, layout_object=self ) context.update({'div': self, 'buttons': buttons}) if isinstance(self.fields[0], Field): # FieldWithButtons(Field('field_name'), StrictButton("go")) # We render the field passing its name and attributes return render_field( self.fields[0][0], form, form_style, context, self.template, attrs=self.fields[0].attrs ) else: return render_field(self.fields[0], form, form_style, context, self.template) class StrictButton(object): """ Layout oject for rendering an HTML button:: Button("button content", css_class="extra") """ template = '%s/layout/button.html' % TEMPLATE_PACK field_classes = 'btn' def __init__(self, content, **kwargs): self.content = content self.template = kwargs.pop('template', self.template) kwargs.setdefault('type', 'button') # We turn css_id and css_class into id and class if 'css_id' in kwargs: kwargs['id'] = kwargs.pop('css_id') kwargs['class'] = self.field_classes if 'css_class' in kwargs: kwargs['class'] += " %s" % kwargs.pop('css_class') self.flat_attrs = flatatt(kwargs) def render(self, form, form_style, context): self.content = Template(text_type(self.content)).render(context) return render_to_string(self.template, Context({'button': self})) class Container(Div): """ Base class used for `Tab` and `AccordionGroup`, represents a basic container concept """ css_class = "" def __init__(self, name, *fields, **kwargs): super(Container, self).__init__(*fields, **kwargs) self.template = kwargs.pop('template', self.template) self.name = name self.active = kwargs.pop("active", False) if not self.css_id: self.css_id = slugify(self.name) def __contains__(self, field_name): """ check if field_name is contained within tab. """ return field_name in map(lambda pointer: pointer[1], self.get_field_names()) def render(self, form, form_style, context): if self.active: if not 'active' in self.css_class: self.css_class += ' active' else: self.css_class = self.css_class.replace('active', '') return super(Container, self).render(form, form_style, context) class ContainerHolder(Div): """ Base class used for `TabHolder` and `Accordion`, groups containers """ def first_container_with_errors(self, errors): """ Returns the first container with errors, otherwise returns the first one """ for tab in self.fields: errors_here = any(error in tab for error in errors) if errors_here: return tab return self.fields[0] class Tab(Container): """ Tab object. It wraps fields in a div whose default class is "tab-pane" and takes a name as first argument. Example:: Tab('tab_name', 'form_field_1', 'form_field_2', 'form_field_3') """ css_class = 'tab-pane' link_template = '%s/layout/tab-link.html' % TEMPLATE_PACK def render_link(self): """ Render the link for the tab-pane. It must be called after render so css_class is updated with active if needed. """ return render_to_string(self.link_template, Context({'link': self})) class TabHolder(ContainerHolder): """ TabHolder object. It wraps Tab objects in a container. Requires bootstrap-tab.js:: TabHolder( Tab('form_field_1', 'form_field_2'), Tab('form_field_3') ) """ template = '%s/layout/tab.html' % TEMPLATE_PACK def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): links, content = '', '' for tab in self.fields: tab.active = False # The first tab with errors will be active self.first_container_with_errors(form.errors.keys()).active = True for tab in self.fields: content += render_field( tab, form, form_style, context, template_pack=template_pack ) links += tab.render_link() return render_to_string(self.template, Context({ 'tabs': self, 'links': links, 'content': content })) class AccordionGroup(Container): """ Accordion Group (pane) object. It wraps given fields inside an accordion tab. It takes accordion tab name as first argument:: AccordionGroup("group name", "form_field_1", "form_field_2") """ template = "%s/accordion-group.html" % TEMPLATE_PACK data_parent = "" # accordion parent div id. class Accordion(ContainerHolder): """ Accordion menu object. It wraps `AccordionGroup` objects in a container:: Accordion( AccordionGroup("group name", "form_field_1", "form_field_2"), AccordionGroup("another group name", "form_field") ) """ template = "%s/accordion.html" % TEMPLATE_PACK def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): content = '' # accordion group needs the parent div id to set `data-parent` (I don't # know why). This needs to be a unique id if not self.css_id: self.css_id = "-".join(["accordion", text_type(randint(1000, 9999))]) # first group with errors or first groupt will be visible, others will be collapsed self.first_container_with_errors(form.errors.keys()).active = True for group in self.fields: group.data_parent = self.css_id content += render_field( group, form, form_style, context, template_pack=template_pack ) return render_to_string( self.template, Context({'accordion': self, 'content': content}) ) class Alert(Div): """ `Alert` generates markup in the form of an alert dialog Alert(content='Warning! Best check yo self, you're not looking too good.') """ template = "bootstrap/layout/alert.html" css_class = "alert" def __init__(self, content, dismiss=True, block=False, **kwargs): fields = [] if block: self.css_class += ' alert-block' Div.__init__(self, *fields, **kwargs) self.template = kwargs.pop('template', self.template) self.content = content self.dismiss = dismiss def render(self, form, form_style, context): return render_to_string( self.template, Context({'alert': self, 'content': self.content, 'dismiss': self.dismiss })) class UneditableField(Field): """ Layout object for rendering fields as uneditable in bootstrap Example:: UneditableField('field_name', css_class="input-xlarge") """ template = "%s/layout/uneditable_input.html" % TEMPLATE_PACK def __init__(self, field, *args, **kwargs): self.attrs = {'class': 'uneditable-input'} super(UneditableField, self).__init__(field, *args, **kwargs) class InlineField(Field): template = "%s/layout/inline_field.html" % TEMPLATE_PACK django-crispy-forms-1.4.0/crispy_forms/compatibility.py000066400000000000000000000004131221066745500233610ustar00rootroot00000000000000import sys PY2 = sys.version_info[0] == 2 if not PY2: text_type = str binary_type = bytes string_types = (str,) integer_types = (int,) else: text_type = unicode binary_type = str string_types = basestring integer_types = (int, long) django-crispy-forms-1.4.0/crispy_forms/exceptions.py000066400000000000000000000005111221066745500226700ustar00rootroot00000000000000class CrispyError(Exception): pass class FormHelpersException(CrispyError): """ This is raised when building a form via helpers throws an error. We want to catch form helper errors as soon as possible because debugging templatetags is never fun. """ pass class DynamicError(CrispyError): pass django-crispy-forms-1.4.0/crispy_forms/helper.py000066400000000000000000000335531221066745500220020ustar00rootroot00000000000000# -*- coding: utf-8 -*- import re from django.core.urlresolvers import reverse, NoReverseMatch from django.utils.safestring import mark_safe from crispy_forms.compatibility import string_types from crispy_forms.layout import Layout from crispy_forms.layout_slice import LayoutSlice from crispy_forms.utils import render_field, flatatt, TEMPLATE_PACK from crispy_forms.exceptions import FormHelpersException class DynamicLayoutHandler(object): def _check_layout(self): if self.layout is None: raise FormHelpersException("You need to set a layout in your FormHelper") def _check_layout_and_form(self): self._check_layout() if self.form is None: raise FormHelpersException("You need to pass a form instance to your FormHelper") def all(self): """ Returns all layout objects of first level of depth """ self._check_layout() return LayoutSlice(self.layout, slice(0, len(self.layout.fields), 1)) def filter(self, *LayoutClasses, **kwargs): """ Returns a LayoutSlice pointing to layout objects of type `LayoutClass` """ self._check_layout() max_level = kwargs.pop('max_level', 0) greedy = kwargs.pop('greedy', False) filtered_layout_objects = self.layout.get_layout_objects(LayoutClasses, max_level=max_level, greedy=greedy) return LayoutSlice(self.layout, filtered_layout_objects) def filter_by_widget(self, widget_type): """ Returns a LayoutSlice pointing to fields with widgets of `widget_type` """ self._check_layout_and_form() layout_field_names = self.layout.get_field_names() # Let's filter all fields with widgets like widget_type filtered_fields = [] for pointer in layout_field_names: if isinstance(self.form.fields[pointer[1]].widget, widget_type): filtered_fields.append(pointer) return LayoutSlice(self.layout, filtered_fields) def exclude_by_widget(self, widget_type): """ Returns a LayoutSlice pointing to fields with widgets NOT matching `widget_type` """ self._check_layout_and_form() layout_field_names = self.layout.get_field_names() # Let's exclude all fields with widgets like widget_type filtered_fields = [] for pointer in layout_field_names: if not isinstance(self.form.fields[pointer[1]].widget, widget_type): filtered_fields.append(pointer) return LayoutSlice(self.layout, filtered_fields) def __getitem__(self, key): """ Return a LayoutSlice that makes changes affect the current instance of the layout and not a copy. """ # when key is a string containing the field name if isinstance(key, string_types): # Django templates access FormHelper attributes using dictionary [] operator # This could be a helper['form_id'] access, not looking for a field if hasattr(self, key): return getattr(self, key) self._check_layout() layout_field_names = self.layout.get_field_names() filtered_field = [] for pointer in layout_field_names: # There can be an empty pointer if len(pointer) == 2 and pointer[1] == key: filtered_field.append(pointer) return LayoutSlice(self.layout, filtered_field) return LayoutSlice(self.layout, key) def __setitem__(self, key, value): self.layout[key] = value def __delitem__(self, key): del self.layout.fields[key] def __len__(self): if self.layout is not None: return len(self.layout.fields) else: return 0 class FormHelper(DynamicLayoutHandler): """ This class controls the form rendering behavior of the form passed to the `{% crispy %}` tag. For doing so you will need to set its attributes and pass the corresponding helper object to the tag:: {% crispy form form.helper %} Let's see what attributes you can set and what form behaviors they apply to: **form_method**: Specifies form method attribute. You can see it to 'POST' or 'GET'. Defaults to 'POST' **form_action**: Applied to the form action attribute: - Can be a named url in your URLconf that can be executed via the `{% url %}` template tag. \ Example: 'show_my_profile'. In your URLconf you could have something like:: url(r'^show/profile/$', 'show_my_profile_view', name = 'show_my_profile') - It can simply point to a URL '/whatever/blabla/'. **form_id**: Generates a form id for dom identification. If no id provided then no id attribute is created on the form. **form_class**: String containing separated CSS clases to be applied to form class attribute. The form will always have by default 'uniForm' class. **form_tag**: It specifies if
tags should be rendered when using a Layout. If set to False it renders the form without the
tags. Defaults to True. **form_error_title**: If a form has `non_field_errors` to display, they are rendered in a div. You can set title's div with this attribute. Example: "Oooops!" or "Form Errors" **formset_error_title**: If a formset has `non_form_errors` to display, they are rendered in a div. You can set title's div with this attribute. **form_style**: Uni-form has two built in different form styles. You can choose your favorite. This can be set to "default" or "inline". Defaults to "default". Public Methods: **add_input(input)**: You can add input buttons using this method. Inputs added using this method will be rendered at the end of the form/formset. **add_layout(layout)**: You can add a `Layout` object to `FormHelper`. The Layout specifies in a simple, clean and DRY way how the form fields should be rendered. You can wrap fields, order them, customize pretty much anything in the form. Best way to add a helper to a form is adding a property named helper to the form that returns customized `FormHelper` object:: from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit class MyForm(forms.Form): title = forms.CharField(_("Title")) @property def helper(self): helper = FormHelper() helper.form_id = 'this-form-rocks' helper.form_class = 'search' helper.add_input(Submit('save', 'save')) [...] return helper You can use it in a template doing:: {% load crispy_forms_tags %} {% crispy form %} """ _form_method = 'post' _form_action = '' _form_style = 'default' form = None form_id = '' form_class = '' layout = None form_tag = True form_error_title = None formset_error_title = None form_show_errors = True render_unmentioned_fields = False render_hidden_fields = False render_required_fields = False _help_text_inline = False _error_text_inline = True html5_required = False form_show_labels = True template = None field_template = None disable_csrf = False label_class = '' label_size = '' field_class = '' def __init__(self, form=None): self.attrs = {} self.inputs = [] if form is not None: self.form = form self.layout = self.build_default_layout(form) def build_default_layout(self, form): return Layout(*form.fields.keys()) def get_form_method(self): return self._form_method def set_form_method(self, method): if method.lower() not in ('get', 'post'): raise FormHelpersException('Only GET and POST are valid in the \ form_method helper attribute') self._form_method = method.lower() # we set properties the old way because we want to support pre-2.6 python form_method = property(get_form_method, set_form_method) def get_form_action(self): try: return reverse(self._form_action) except NoReverseMatch: return self._form_action def set_form_action(self, action): self._form_action = action # we set properties the old way because we want to support pre-2.6 python form_action = property(get_form_action, set_form_action) def get_form_style(self): if self._form_style == "default": return '' if self._form_style == "inline": return 'inlineLabels' def set_form_style(self, style): if style.lower() not in ('default', 'inline'): raise FormHelpersException('Only default and inline are valid in the \ form_style helper attribute') self._form_style = style.lower() form_style = property(get_form_style, set_form_style) def get_help_text_inline(self): return self._help_text_inline def set_help_text_inline(self, flag): self._help_text_inline = flag self._error_text_inline = not flag help_text_inline = property(get_help_text_inline, set_help_text_inline) def get_error_text_inline(self): return self._error_text_inline def set_error_text_inline(self, flag): self._error_text_inline = flag self._help_text_inline = not flag error_text_inline = property(get_error_text_inline, set_error_text_inline) def add_input(self, input_object): self.inputs.append(input_object) def add_layout(self, layout): self.layout = layout def render_layout(self, form, context, template_pack=TEMPLATE_PACK): """ Returns safe html of the rendering of the layout """ form.rendered_fields = set() form.crispy_field_template = self.field_template # This renders the specifed Layout strictly html = self.layout.render( form, self.form_style, context, template_pack=template_pack ) # Rendering some extra fields if specified if self.render_unmentioned_fields or self.render_hidden_fields or self.render_required_fields: fields = set(form.fields.keys()) left_fields_to_render = fields - form.rendered_fields for field in left_fields_to_render: if ( self.render_unmentioned_fields or self.render_hidden_fields and form.fields[field].widget.is_hidden or self.render_required_fields and form.fields[field].widget.is_required ): html += render_field( field, form, self.form_style, context, template_pack=template_pack ) # If the user has Meta.fields defined, not included in the layout, # we suppose they need to be rendered if hasattr(form, 'Meta'): if hasattr(form.Meta, 'fields'): current_fields = set(getattr(form, 'fields', [])) meta_fields = set(getattr(form.Meta, 'fields')) fields_to_render = current_fields & meta_fields left_fields_to_render = fields_to_render - form.rendered_fields for field in left_fields_to_render: html += render_field(field, form, self.form_style, context) return mark_safe(html) def get_attributes(self, template_pack=TEMPLATE_PACK): """ Used by crispy_forms_tags to get helper attributes """ items = {} items['form_method'] = self.form_method.strip() items['form_tag'] = self.form_tag items['form_style'] = self.form_style.strip() items['form_show_errors'] = self.form_show_errors items['help_text_inline'] = self.help_text_inline items['error_text_inline'] = self.error_text_inline items['html5_required'] = self.html5_required items['form_show_labels'] = self.form_show_labels items['disable_csrf'] = self.disable_csrf items['label_class'] = self.label_class items['field_class'] = self.field_class label_size_match = re.match('col-lg-(\d+)', self.label_class) if label_size_match: try: items['label_size'] = int(label_size_match.groups()[0]) except: pass items['attrs'] = {} if self.attrs: items['attrs'] = self.attrs.copy() if self.form_action: items['attrs']['action'] = self.form_action.strip() if self.form_id: items['attrs']['id'] = self.form_id.strip() if self.form_class: # uni_form TEMPLATE PACK has a uniForm class by default if template_pack == 'uni_form': items['attrs']['class'] = "uniForm %s" % self.form_class.strip() else: items['attrs']['class'] = self.form_class.strip() else: if template_pack == 'uni_form': items['attrs']['class'] = self.attrs.get('class', '') + " uniForm" items['flat_attrs'] = flatatt(items['attrs']) if self.inputs: items['inputs'] = self.inputs if self.form_error_title: items['form_error_title'] = self.form_error_title.strip() if self.formset_error_title: items['formset_error_title'] = self.formset_error_title.strip() for attribute_name, value in self.__dict__.items(): if attribute_name not in items and attribute_name not in ['layout', 'inputs'] and not attribute_name.startswith('_'): items[attribute_name] = value return items django-crispy-forms-1.4.0/crispy_forms/layout.py000066400000000000000000000353511221066745500220360ustar00rootroot00000000000000import warnings from django.conf import settings from django.template import Context, Template from django.template.loader import render_to_string from django.utils.html import conditional_escape from crispy_forms.compatibility import string_types, text_type from crispy_forms.utils import render_field, flatatt TEMPLATE_PACK = getattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap') class LayoutObject(object): def __getitem__(self, slice): return self.fields[slice] def __setitem__(self, slice, value): self.fields[slice] = value def __delitem__(self, slice): del self.fields[slice] def __len__(self): return len(self.fields) def __getattr__(self, name): """ This allows us to access self.fields list methods like append or insert, without having to declaee them one by one """ # Check necessary for unpickling, see #107 if 'fields' in self.__dict__ and hasattr(self.fields, name): return getattr(self.fields, name) else: return object.__getattribute__(self, name) def get_field_names(self, index=None): """ Returns a list of lists, those lists are named pointers. First parameter is the location of the field, second one the name of the field. Example:: [ [[0,1,2], 'field_name1'], [[0,3], 'field_name2'] ] """ return self.get_layout_objects(string_types, greedy=True) def get_layout_objects(self, *LayoutClasses, **kwargs): """ Returns a list of lists pointing to layout objects of any type matching `LayoutClasses`:: [ [[0,1,2], 'div'], [[0,3], 'field_name'] ] :param max_level: An integer that indicates max level depth to reach when traversing a layout. :param greedy: Boolean that indicates whether to be greedy. If set, max_level is skipped. """ index = kwargs.pop('index', None) max_level = kwargs.pop('max_level', 0) greedy = kwargs.pop('greedy', False) pointers = [] if index is not None and not isinstance(index, list): index = [index] elif index is None: index = [] for i, layout_object in enumerate(self.fields): if isinstance(layout_object, LayoutClasses): if len(LayoutClasses) == 1 and LayoutClasses[0] == string_types: pointers.append([index + [i], layout_object]) else: pointers.append([index + [i], layout_object.__class__.__name__.lower()]) # If it's a layout object and we haven't reached the max depth limit or greedy # we recursive call if hasattr(layout_object, 'get_field_names') and (len(index) < max_level or greedy): new_kwargs = {'index': index + [i], 'max_level': max_level, 'greedy': greedy} pointers = pointers + layout_object.get_layout_objects(*LayoutClasses, **new_kwargs) return pointers class Layout(LayoutObject): """ Form Layout. It is conformed by Layout objects: `Fieldset`, `Row`, `Column`, `MultiField`, `HTML`, `ButtonHolder`, `Button`, `Hidden`, `Reset`, `Submit` and fields. Form fields have to be strings. Layout objects `Fieldset`, `Row`, `Column`, `MultiField` and `ButtonHolder` can hold other Layout objects within. Though `ButtonHolder` should only hold `HTML` and BaseInput inherited classes: `Button`, `Hidden`, `Reset` and `Submit`. You need to add your `Layout` to the `FormHelper` using its method `add_layout`. Example:: layout = Layout( Fieldset('Company data', 'is_company' ), Fieldset(_('Contact details'), 'email', Row('password1', 'password2'), 'first_name', 'last_name', HTML(''), 'company' ), ButtonHolder( Submit('Save', 'Save', css_class='button white'), ), ) helper.add_layout(layout) """ def __init__(self, *fields): self.fields = list(fields) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): html = "" for field in self.fields: html += render_field( field, form, form_style, context, template_pack=template_pack ) return html class ButtonHolder(LayoutObject): """ Layout object. It wraps fields in a
This is where you should put Layout objects that render to form buttons like Submit. It should only hold `HTML` and `BaseInput` inherited objects. Example:: ButtonHolder( HTML(Information Saved), Submit('Save', 'Save') ) """ template = "uni_form/layout/buttonholder.html" def __init__(self, *fields, **kwargs): self.fields = list(fields) self.css_class = kwargs.get('css_class', None) self.css_id = kwargs.get('css_id', None) self.template = kwargs.get('template', self.template) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): html = u'' for field in self.fields: html += render_field(field, form, form_style, context, template_pack=template_pack) return render_to_string(self.template, Context({'buttonholder': self, 'fields_output': html})) class BaseInput(object): """ A base class to reduce the amount of code in the Input classes. """ template = "%s/layout/baseinput.html" % TEMPLATE_PACK def __init__(self, name, value, **kwargs): self.name = name self.value = value self.id = kwargs.pop('css_id', '') self.attrs = {} if 'css_class' in kwargs: self.field_classes += ' %s' % kwargs.pop('css_class') self.template = kwargs.pop('template', self.template) self.flat_attrs = flatatt(kwargs) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): """ Renders an `` if container is used as a Layout object. Input button value can be a variable in context. """ self.value = Template(text_type(self.value)).render(context) return render_to_string(self.template, Context({'input': self})) class Submit(BaseInput): """ Used to create a Submit button descriptor for the {% crispy %} template tag:: submit = Submit('Search the Site', 'search this site') .. note:: The first argument is also slugified and turned into the id for the submit button. """ input_type = 'submit' field_classes = 'submit submitButton' if TEMPLATE_PACK == 'uni_form' else 'btn btn-primary' class Button(BaseInput): """ Used to create a Submit input descriptor for the {% crispy %} template tag:: button = Button('Button 1', 'Press Me!') .. note:: The first argument is also slugified and turned into the id for the button. """ input_type = 'button' field_classes = 'button' if TEMPLATE_PACK == 'uni_form' else 'btn' class Hidden(BaseInput): """ Used to create a Hidden input descriptor for the {% crispy %} template tag. """ input_type = 'hidden' field_classes = 'hidden' class Reset(BaseInput): """ Used to create a Reset button input descriptor for the {% crispy %} template tag:: reset = Reset('Reset This Form', 'Revert Me!') .. note:: The first argument is also slugified and turned into the id for the reset. """ input_type = 'reset' field_classes = 'reset resetButton' if TEMPLATE_PACK == 'uni_form' else 'btn btn-inverse' class Fieldset(LayoutObject): """ Layout object. It wraps fields in a
Example:: Fieldset("Text for the legend", 'form_field_1', 'form_field_2' ) The first parameter is the text for the fieldset legend. This text is context aware, so you can do things like:: Fieldset("Data for {{ user.username }}", 'form_field_1', 'form_field_2' ) """ template = "uni_form/layout/fieldset.html" def __init__(self, legend, *fields, **kwargs): self.fields = list(fields) self.legend = legend self.css_class = kwargs.pop('css_class', '') self.css_id = kwargs.pop('css_id', None) # Overrides class variable with an instance level variable self.template = kwargs.pop('template', self.template) self.flat_attrs = flatatt(kwargs) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): fields = '' for field in self.fields: fields += render_field(field, form, form_style, context, template_pack=template_pack) legend = '' if self.legend: legend = u'%s' % Template(text_type(self.legend)).render(context) return render_to_string(self.template, Context({'fieldset': self, 'legend': legend, 'fields': fields, 'form_style': form_style})) class MultiField(LayoutObject): """ MultiField container. Renders to a MultiField
""" template = "uni_form/layout/multifield.html" field_template = "uni_form/multifield.html" def __init__(self, label, *fields, **kwargs): self.fields = list(fields) self.label_html = label self.label_class = kwargs.pop('label_class', u'blockLabel') self.css_class = kwargs.pop('css_class', u'ctrlHolder') self.css_id = kwargs.pop('css_id', None) self.template = kwargs.pop('template', self.template) self.field_template = kwargs.pop('field_template', self.field_template) self.flat_attrs = flatatt(kwargs) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): # If a field within MultiField contains errors if context['form_show_errors']: for field in map(lambda pointer: pointer[1], self.get_field_names()): if field in form.errors: self.css_class += " error" fields_output = u'' for field in self.fields: fields_output += render_field( field, form, form_style, context, self.field_template, self.label_class, layout_object=self, template_pack=template_pack ) context.update({'multifield': self, 'fields_output': fields_output}) return render_to_string(self.template, context) class Div(LayoutObject): """ Layout object. It wraps fields in a
You can set `css_id` for a DOM id and `css_class` for a DOM class. Example:: Div('form_field_1', 'form_field_2', css_id='div-example', css_class='divs') """ template = "uni_form/layout/div.html" def __init__(self, *fields, **kwargs): self.fields = list(fields) if hasattr(self, 'css_class') and 'css_class' in kwargs: self.css_class += ' %s' % kwargs.pop('css_class') if not hasattr(self, 'css_class'): self.css_class = kwargs.pop('css_class', None) self.css_id = kwargs.pop('css_id', '') self.template = kwargs.pop('template', self.template) self.flat_attrs = flatatt(kwargs) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): fields = '' for field in self.fields: fields += render_field(field, form, form_style, context, template_pack=template_pack) return render_to_string(self.template, Context({'div': self, 'fields': fields})) class Row(Div): """ Layout object. It wraps fields in a div whose default class is "formRow". Example:: Row('form_field_1', 'form_field_2', 'form_field_3') """ css_class = 'formRow' if TEMPLATE_PACK == 'uni_form' else 'row' class Column(Div): """ Layout object. It wraps fields in a div whose default class is "formColumn". Example:: Column('form_field_1', 'form_field_2') """ css_class = 'formColumn' class HTML(object): """ Layout object. It can contain pure HTML and it has access to the whole context of the page where the form is being rendered. Examples:: HTML("{% if saved %}Data saved{% endif %}") HTML('') """ def __init__(self, html): self.html = html def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): return Template(text_type(self.html)).render(context) class Field(LayoutObject): """ Layout object, It contains one field name, and you can add attributes to it easily. For setting class attributes, you need to use `css_class`, as `class` is a Python keyword. Example:: Field('field_name', style="color: #333;", css_class="whatever", id="field_name") """ template = "%s/field.html" % TEMPLATE_PACK def __init__(self, *args, **kwargs): self.fields = list(args) if not hasattr(self, 'attrs'): self.attrs = {} if 'css_class' in kwargs: if 'class' in self.attrs: self.attrs['class'] += " %s" % kwargs.pop('css_class') else: self.attrs['class'] = kwargs.pop('css_class') self.wrapper_class = kwargs.pop('wrapper_class', None) self.template = kwargs.pop('template', self.template) # We use kwargs as HTML attributes, turning data_id='test' into data-id='test' self.attrs.update(dict([(k.replace('_', '-'), conditional_escape(v)) for k, v in kwargs.items()])) def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): if hasattr(self, 'wrapper_class'): context['wrapper_class'] = self.wrapper_class html = '' for field in self.fields: html += render_field(field, form, form_style, context, template=self.template, attrs=self.attrs, template_pack=template_pack) return html class MultiWidgetField(Field): """ Layout object. For fields with :class:`~django.forms.MultiWidget` as `widget`, you can pass additional attributes to each widget. Example:: MultiWidgetField( 'multiwidget_field_name', attrs=( {'style': 'width: 30px;'}, {'class': 'second_widget_class'} ), ) .. note:: To override widget's css class use ``class`` not ``css_class``. """ def __init__(self, *args, **kwargs): self.fields = list(args) self.attrs = kwargs.pop('attrs', {}) self.template = kwargs.pop('template', self.template) django-crispy-forms-1.4.0/crispy_forms/layout_slice.py000066400000000000000000000140351221066745500232110ustar00rootroot00000000000000# -*- coding: utf-8 -*- from crispy_forms.compatibility import integer_types, string_types from crispy_forms.exceptions import DynamicError from crispy_forms.layout import Fieldset, MultiField from crispy_forms.bootstrap import Container class LayoutSlice(object): # List of layout objects that need args passed first before fields args_first = (Fieldset, MultiField, Container) def __init__(self, layout, key): self.layout = layout if isinstance(key, integer_types): self.slice = slice(key, key+1, 1) else: self.slice = key def wrapped_object(self, LayoutClass, fields, *args, **kwargs): """ Returns a layout object of type `LayoutClass` with `args` and `kwargs` that wraps `fields` inside. """ if args: if isinstance(fields, list): fields= tuple(fields) else: fields = (fields,) if LayoutClass in self.args_first: arguments = args + fields else: arguments = fields + args return LayoutClass(*arguments, **kwargs) else: if isinstance(fields, list): return LayoutClass(*fields, **kwargs) else: return LayoutClass(fields, **kwargs) def pre_map(self, function): """ Iterates over layout objects pointed in `self.slice` executing `function` on them. It passes `function` penultimate layout object and the position where to find last one """ if isinstance(self.slice, slice): for i in range(*self.slice.indices(len(self.layout.fields))): function(self.layout, i) elif isinstance(self.slice, list): # A list of pointers Ex: [[[0, 0], 'div'], [[0, 2, 3], 'field_name']] for pointer in self.slice: position = pointer[0] # If it's pointing first level if len(position) == 1: function(self.layout, position[-1]) else: layout_object = self.layout.fields[position[0]] for i in position[1:-1]: layout_object = layout_object.fields[i] try: function(layout_object, position[-1]) except IndexError: # We could avoid this exception, recalculating pointers. # However this case is most of the time an undesired behavior raise DynamicError("Trying to wrap a field within an already wrapped field, \ recheck your filter or layout") def wrap(self, LayoutClass, *args, **kwargs): """ Wraps every layout object pointed in `self.slice` under a `LayoutClass` instance with `args` and `kwargs` passed. """ def wrap_object(layout_object, j): layout_object.fields[j] = self.wrapped_object( LayoutClass, layout_object.fields[j], *args, **kwargs ) self.pre_map(wrap_object) def wrap_once(self, LayoutClass, *args, **kwargs): """ Wraps every layout object pointed in `self.slice` under a `LayoutClass` instance with `args` and `kwargs` passed, unless layout object's parent is already a subclass of `LayoutClass`. """ def wrap_object_once(layout_object, j): if not isinstance(layout_object, LayoutClass): layout_object.fields[j] = self.wrapped_object( LayoutClass, layout_object.fields[j], *args, **kwargs ) self.pre_map(wrap_object_once) def wrap_together(self, LayoutClass, *args, **kwargs): """ Wraps all layout objects pointed in `self.slice` together under a `LayoutClass` instance with `args` and `kwargs` passed. """ if isinstance(self.slice, slice): # The start of the slice is replaced start = self.slice.start if self.slice.start is not None else 0 self.layout.fields[start] = self.wrapped_object( LayoutClass, self.layout.fields[self.slice], *args, **kwargs ) # The rest of places of the slice are removed, as they are included in the previous for i in reversed(range(*self.slice.indices(len(self.layout.fields)))): if i != start: del self.layout.fields[i] elif isinstance(self.slice, list): raise DynamicError("wrap_together doesn't work with filter, only with [] operator") def map(self, function): """ Iterates over layout objects pointed in `self.slice` executing `function` on them It passes `function` last layout object """ if isinstance(self.slice, slice): for i in range(*self.slice.indices(len(self.layout.fields))): function(self.layout.fields[i]) elif isinstance(self.slice, list): # A list of pointers Ex: [[[0, 0], 'div'], [[0, 2, 3], 'field_name']] for pointer in self.slice: position = pointer[0] layout_object = self.layout.fields[position[0]] for i in position[1:]: previous_layout_object = layout_object layout_object = layout_object.fields[i] # If update_attrs is applied to a string, we call to its wrapping layout object if ( function.__name__ == 'update_attrs' and isinstance(layout_object, string_types) ): function(previous_layout_object) else: function(layout_object) def update_attributes(self, **kwargs): """ Updates attributes of every layout object pointed in `self.slice` using kwargs """ def update_attrs(layout_object): if hasattr(layout_object, 'attrs'): layout_object.attrs.update(kwargs) self.map(update_attrs) django-crispy-forms-1.4.0/crispy_forms/models.py000066400000000000000000000000001221066745500217630ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/000077500000000000000000000000001221066745500221365ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/000077500000000000000000000000001221066745500241535ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/accordion-group.html000066400000000000000000000006401221066745500301340ustar00rootroot00000000000000
{{ fields|safe }}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/accordion.html000066400000000000000000000001221221066745500267750ustar00rootroot00000000000000
{{ content|safe }}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/betterform.html000066400000000000000000000012331221066745500272110ustar00rootroot00000000000000{% for fieldset in form.fieldsets %}
{% if fieldset.legend %} {{ fieldset.legend }} {% endif %} {% if fieldset.description %}

{{ fieldset.description }}

{% endif %} {% for field in fieldset %} {% if field.is_hidden %} {{ field }} {% else %} {% include "bootstrap/field.html" %} {% endif %} {% endfor %} {% if not forloop.last or not fieldset_open %}
{% endif %} {% endfor %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/display_form.html000066400000000000000000000003201221066745500275240ustar00rootroot00000000000000{% if form.form_html %} {% if form_show_errors %} {% include "bootstrap/errors.html" %} {% endif %} {{ form.form_html }} {% else %} {% include "bootstrap/uni_form.html" %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/errors.html000066400000000000000000000004321221066745500263540ustar00rootroot00000000000000{% if form.non_field_errors %}
{% if form_error_title %}

{{ form_error_title }}

{% endif %}
    {{ form.non_field_errors|unordered_list }}
{% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/errors_formset.html000066400000000000000000000004451221066745500301170ustar00rootroot00000000000000{% if formset.non_form_errors %}
{% if formset_error_title %}

{{ formset_error_title }}

{% endif %}
    {{ formset.non_form_errors|unordered_list }}
{% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/field.html000066400000000000000000000033241221066745500261260ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %} <{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="control-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} error{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}"> {% if field.label and not field|is_checkbox and form_show_labels %} {% endif %} {% if field|is_checkboxselectmultiple %} {% include 'bootstrap/layout/checkboxselectmultiple.html' %} {% endif %} {% if field|is_radioselect %} {% include 'bootstrap/layout/radioselect.html' %} {% endif %} {% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %} {% else %} {% crispy_field field %} {% include 'bootstrap/layout/help_text_and_errors.html' %} {% endif %}
{% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/000077500000000000000000000000001221066745500254705ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/alert.html000066400000000000000000000004011221066745500274600ustar00rootroot00000000000000 {% if dismiss %}{% endif %} {{ content|safe }}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/baseinput.html000066400000000000000000000006541221066745500303550ustar00rootroot00000000000000 django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/button.html000066400000000000000000000001101221066745500276610ustar00rootroot00000000000000 django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/checkboxselectmultiple.html000066400000000000000000000014251221066745500331220ustar00rootroot00000000000000{% load crispy_forms_filters %} {% load l10n %}
{% include 'bootstrap/layout/field_errors_block.html' %} {% for choice in field.field.choices %} {% endfor %} {% include 'bootstrap/layout/help_text.html' %}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/checkboxselectmultiple_inline.html000066400000000000000000000011731221066745500344600ustar00rootroot00000000000000{% if field.is_hidden %} {{ field }} {% else %}
{% if field.label %} {% endif %} {% include 'bootstrap/layout/checkboxselectmultiple.html' %}
{% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/field_errors.html000066400000000000000000000003471221066745500310410ustar00rootroot00000000000000{% if form_show_errors and field.errors %} {% for error in field.errors %} {{ error }} {% endfor %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/field_errors_block.html000066400000000000000000000003401221066745500322040ustar00rootroot00000000000000{% if form_show_errors and field.errors %} {% for error in field.errors %}

{{ error }}

{% endfor %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/field_with_buttons.html000066400000000000000000000015261221066745500322560ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.label and form_show_labels %} {% endif %}
{% crispy_field field %} {{ buttons|safe }}
{% include 'bootstrap/layout/help_text_and_errors.html' %}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/formactions.html000066400000000000000000000002061221066745500307000ustar00rootroot00000000000000 {{ fields_output|safe }}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/help_text.html000066400000000000000000000004371221066745500303560ustar00rootroot00000000000000{% if field.help_text %} {% if help_text_inline %} {{ field.help_text|safe }} {% else %}

{{ field.help_text|safe }}

{% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/help_text_and_errors.html000066400000000000000000000005721221066745500325740ustar00rootroot00000000000000{% if help_text_inline and not error_text_inline %} {% include 'bootstrap/layout/help_text.html' %} {% endif %} {% if error_text_inline %} {% include 'bootstrap/layout/field_errors.html' %} {% else %} {% include 'bootstrap/layout/field_errors_block.html' %} {% endif %} {% if not help_text_inline %} {% include 'bootstrap/layout/help_text.html' %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/multifield.html000066400000000000000000000010251221066745500305120ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %} {% if field.label %} {% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/prepended_appended_text.html000066400000000000000000000023221221066745500332270ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %}
{% if field.label and form_show_labels %} {% endif %}
{% if crispy_prepended_text %}{{ crispy_prepended_text|safe }}{% endif %} {% crispy_field field %} {% if crispy_appended_text %}{{ crispy_appended_text|safe }}{% endif %}
{% include 'bootstrap/layout/help_text_and_errors.html' %}
{% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/radioselect.html000066400000000000000000000013101221066745500306470ustar00rootroot00000000000000{% load crispy_forms_filters %} {% load l10n %}
{% include 'bootstrap/layout/field_errors_block.html' %} {% for choice in field.field.choices %} {% endfor %} {% include 'bootstrap/layout/help_text.html' %}
django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/radioselect_inline.html000066400000000000000000000011601221066745500322100ustar00rootroot00000000000000{% if field.is_hidden %} {{ field }} {% else %}
{% if field.label %} {% endif %} {% include 'bootstrap/layout/radioselect.html' %}
{% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/tab-link.html000066400000000000000000000002721221066745500300600ustar00rootroot00000000000000
  • {{ link.name|capfirst }}{% if tab.errors %}!{% endif %}
  • django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/tab.html000066400000000000000000000002431221066745500271230ustar00rootroot00000000000000 {{ links|safe }}
    {{ content|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/layout/uneditable_input.html000066400000000000000000000010601221066745500317060ustar00rootroot00000000000000
    {{ field.label|safe }}{% if field.field.required %}*{% endif %}
    {% if field.value %}{{ field.value }}{% endif %} {% include 'bootstrap/layout/help_text.html' %}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/table_inline_formset.html000066400000000000000000000037171221066745500312350ustar00rootroot00000000000000{% load crispy_forms_tags %} {% load crispy_forms_utils %} {% load crispy_forms_field %} {% specialspaceless %} {% if formset_tag %}
    {% endif %} {% if formset_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %}
    {{ formset.management_form|crispy }}
    {% if formset.readonly and not formset.queryset.exists %} {% else %} {% for field in formset.forms.0 %} {% if field.label and not field|is_checkbox and not field.is_hidden %} {{ field.label|safe }}{% if field.field.required %}*{% endif %} {% endif %} {% endfor %} {% endif %} {% for form in formset %} {% if form_show_errors and not form.is_extra %} {% include "bootstrap/errors.html" %} {% endif %} {% for field in form %} {% include 'bootstrap/field.html' with tag="th" form_show_labels=False %} {% endfor %} {% endfor %} {% if inputs %}
    {% for input in inputs %} {% include "uni_form/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if formset_tag %}{% endif %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/uni_form.html000066400000000000000000000003561221066745500266630ustar00rootroot00000000000000{% load crispy_forms_utils %} {% specialspaceless %} {% if form_show_errors %} {% include "bootstrap/errors.html" %} {% endif %} {% for field in form %} {% include "bootstrap/field.html" %} {% endfor %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/uni_formset.html000066400000000000000000000003441221066745500273740ustar00rootroot00000000000000{% with formset.management_form as form %} {% include 'bootstrap/uni_form.html' %} {% endwith %} {% for form in formset %}
    {% include 'bootstrap/uni_form.html' %}
    {% endfor %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/whole_uni_form.html000066400000000000000000000011721221066745500300560ustar00rootroot00000000000000{% load crispy_forms_utils %} {% specialspaceless %} {% if form_tag %}
    {% endif %} {% if form_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %} {% include "bootstrap/display_form.html" %} {% if inputs %}
    {% for input in inputs %} {% include "bootstrap/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if form_tag %}
    {% endif %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap/whole_uni_formset.html000066400000000000000000000015161221066745500305740ustar00rootroot00000000000000{% load crispy_forms_tags %} {% load crispy_forms_utils %} {% specialspaceless %} {% if formset_tag %}
    {% endif %} {% if formset_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %}
    {{ formset.management_form|crispy }}
    {% include "bootstrap/errors_formset.html" %} {% for form in formset %} {% include "bootstrap/display_form.html" %} {% endfor %} {% if inputs %}
    {% for input in inputs %} {% include "bootstrap/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if formset_tag %}
    {% endif %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/000077500000000000000000000000001221066745500242365ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/accordion-group.html000066400000000000000000000007161221066745500302230ustar00rootroot00000000000000
    {{ fields|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/accordion.html000066400000000000000000000001241221066745500270620ustar00rootroot00000000000000
    {{ content|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/betterform.html000066400000000000000000000012341221066745500272750ustar00rootroot00000000000000{% for fieldset in form.fieldsets %}
    {% if fieldset.legend %} {{ fieldset.legend }} {% endif %} {% if fieldset.description %}

    {{ fieldset.description }}

    {% endif %} {% for field in fieldset %} {% if field.is_hidden %} {{ field }} {% else %} {% include "bootstrap3/field.html" %} {% endif %} {% endfor %} {% if not forloop.last or not fieldset_open %}
    {% endif %} {% endfor %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/display_form.html000066400000000000000000000003221221066745500276110ustar00rootroot00000000000000{% if form.form_html %} {% if form_show_errors %} {% include "bootstrap3/errors.html" %} {% endif %} {{ form.form_html }} {% else %} {% include "bootstrap3/uni_form.html" %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/errors.html000066400000000000000000000004331221066745500264400ustar00rootroot00000000000000{% if form.non_field_errors %}
    {% if form_error_title %}

    {{ form_error_title }}

    {% endif %}
      {{ form.non_field_errors|unordered_list }}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/errors_formset.html000066400000000000000000000004461221066745500302030ustar00rootroot00000000000000{% if formset.non_form_errors %}
    {% if formset_error_title %}

    {{ formset_error_title }}

    {% endif %}
      {{ formset.non_form_errors|unordered_list }}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/field.html000066400000000000000000000042711221066745500262130ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %} {% if field|is_checkbox %}
    {% endif %} <{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" {% if not field|is_checkbox %}class="form-group{% else %}class="checkbox{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} has-error{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}"> {% if field.label and not field|is_checkbox and form_show_labels %} {% endif %} {% if field|is_checkboxselectmultiple %} {% include 'bootstrap3/layout/checkboxselectmultiple.html' %} {% endif %} {% if field|is_radioselect %} {% include 'bootstrap3/layout/radioselect.html' %} {% endif %} {% if not field|is_checkboxselectmultiple and not field|is_radioselect %} {% if field|is_checkbox and form_show_labels %} {% if label_class %}
    {% endif %} {% if label_class %}
    {% endif %} {% else %}
    {% crispy_field field %} {% include 'bootstrap3/layout/help_text_and_errors.html' %}
    {% endif %} {% endif %} {% if field|is_checkbox %}
    {% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/field.html.bk000066400000000000000000000043051221066745500266040ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %} {% if field|is_checkbox %}
    {% endif %} <{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" {% if not field|is_checkbox %}class="form-group{% else %}class="checkbox{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} has-error{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}"> {% if field.label and not field|is_checkbox and form_show_labels %} {% endif %} {% if field|is_checkboxselectmultiple %} {% include 'bootstrap3/layout/checkboxselectmultiple.html' %} {% endif %} {% if field|is_radioselect %} {% include 'bootstrap3/layout/radioselect.html' %} {% endif %} {% if not field|is_checkboxselectmultiple and not field|is_radioselect %} {% if field|is_checkbox and form_show_labels %} {% if label_class %}
    {% endif %} {% if label_class %}
    {% endif %} {% else %}
    {% crispy_field field %} {% include 'bootstrap3/layout/help_text_and_errors.html' %}
    {% endif %} {% endif %} {% if field|is_checkbox %}
    {% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/field.strict.html000066400000000000000000000021161221066745500275160ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %}
    {% for error in field.errors %}

    {{ error }}

    {% endfor %} {% if field|is_checkbox %} {% crispy_field field %} {% endif %} {% if field.label %} {% endif %} {% if not field|is_checkbox %} {% crispy_field field %} {% endif %} {% if field.help_text %}

    {{ field.help_text|safe }}

    {% endif %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/000077500000000000000000000000001221066745500255535ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/baseinput.html000066400000000000000000000006541221066745500304400ustar00rootroot00000000000000 django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/button.html000066400000000000000000000001101221066745500277440ustar00rootroot00000000000000 django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/checkboxselectmultiple.html000066400000000000000000000014511221066745500332040ustar00rootroot00000000000000{% load crispy_forms_filters %} {% load l10n %}
    {% include 'bootstrap3/layout/field_errors_block.html' %} {% for choice in field.field.choices %} {% endfor %} {% include 'bootstrap3/layout/help_text.html' %}
    checkboxselectmultiple_inline.html000066400000000000000000000012171221066745500344630ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout{% if field.is_hidden %} {{ field }} {% else %}
    {% if field.label %} {% endif %} {% include 'bootstrap3/layout/checkboxselectmultiple.html' %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/field_errors.html000066400000000000000000000003461221066745500311230ustar00rootroot00000000000000{% if form_show_errors and field.errors %} {% for error in field.errors %} {{ error }} {% endfor %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/field_errors_block.html000066400000000000000000000003401221066745500322670ustar00rootroot00000000000000{% if form_show_errors and field.errors %} {% for error in field.errors %}

    {{ error }}

    {% endfor %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/field_with_buttons.html000066400000000000000000000017601221066745500323410ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.label and form_show_labels %} {% endif %}
    {% crispy_field field %} {{ buttons|safe }}
    {% include 'bootstrap3/layout/help_text_and_errors.html' %}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/formactions.html000066400000000000000000000002061221066745500307630ustar00rootroot00000000000000 {{ fields_output|safe }} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/help_text.html000066400000000000000000000004361221066745500304400ustar00rootroot00000000000000{% if field.help_text %} {% if help_text_inline %} {{ field.help_text|safe }} {% else %}

    {{ field.help_text|safe }}

    {% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/help_text_and_errors.html000066400000000000000000000005761221066745500326630ustar00rootroot00000000000000{% if help_text_inline and not error_text_inline %} {% include 'bootstrap3/layout/help_text.html' %} {% endif %} {% if error_text_inline %} {% include 'bootstrap3/layout/field_errors.html' %} {% else %} {% include 'bootstrap3/layout/field_errors_block.html' %} {% endif %} {% if not help_text_inline %} {% include 'bootstrap3/layout/help_text.html' %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/inline_field.html000066400000000000000000000014201221066745500310570ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %} {% if field|is_checkbox %}
    {% else %}
    {% crispy_field field 'placeholder' field.label %}
    {% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/multifield.html000066400000000000000000000010251221066745500305750ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %} {% if field.label %} {% endif %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/prepended_appended_text.html000066400000000000000000000024141221066745500333140ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %}
    {% if field.label and form_show_labels %} {% endif %}
    {% if crispy_prepended_text %}{{ crispy_prepended_text|safe }}{% endif %} {% crispy_field field %} {% if crispy_appended_text %}{{ crispy_appended_text|safe }}{% endif %}
    {% include 'bootstrap3/layout/help_text_and_errors.html' %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/radioselect.html000066400000000000000000000013341221066745500307400ustar00rootroot00000000000000{% load crispy_forms_filters %} {% load l10n %}
    {% include 'bootstrap3/layout/field_errors_block.html' %} {% for choice in field.field.choices %} {% endfor %} {% include 'bootstrap3/layout/help_text.html' %}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/radioselect_inline.html000066400000000000000000000012041221066745500322720ustar00rootroot00000000000000{% if field.is_hidden %} {{ field }} {% else %}
    {% if field.label %} {% endif %} {% include 'bootstrap3/layout/radioselect.html' %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/tab-link.html000066400000000000000000000002721221066745500301430ustar00rootroot00000000000000
  • {{ link.name|capfirst }}{% if tab.errors %}!{% endif %}
  • django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/tab.html000066400000000000000000000002561221066745500272120ustar00rootroot00000000000000 {{ links|safe }}
    {{ content|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/layout/uneditable_input.html000066400000000000000000000011211221066745500317670ustar00rootroot00000000000000{% load crispy_forms_field %}
    {% crispy_field field 'disabled' 'disabled' %} {% include 'bootstrap3/layout/help_text.html' %}
    django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/table_inline_formset.html000066400000000000000000000037211221066745500313130ustar00rootroot00000000000000{% load crispy_forms_tags %} {% load crispy_forms_utils %} {% load crispy_forms_field %} {% specialspaceless %} {% if formset_tag %}
    {% endif %} {% if formset_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %}
    {{ formset.management_form|crispy }}
    {% if formset.readonly and not formset.queryset.exists %} {% else %} {% for field in formset.forms.0 %} {% if field.label and not field|is_checkbox and not field.is_hidden %} {{ field.label|safe }}{% if field.field.required %}*{% endif %} {% endif %} {% endfor %} {% endif %} {% for form in formset %} {% if form_show_errors and not form.is_extra %} {% include "bootstrap3/errors.html" %} {% endif %} {% for field in form %} {% include 'bootstrap3/field.html' with tag="th" form_show_labels=False %} {% endfor %} {% endfor %} {% if inputs %}
    {% for input in inputs %} {% include "uni_form/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if formset_tag %}{% endif %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/uni_form.html000066400000000000000000000003601221066745500267410ustar00rootroot00000000000000{% load crispy_forms_utils %} {% specialspaceless %} {% if form_show_errors %} {% include "bootstrap3/errors.html" %} {% endif %} {% for field in form %} {% include "bootstrap3/field.html" %} {% endfor %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/uni_formset.html000066400000000000000000000003461221066745500274610ustar00rootroot00000000000000{% with formset.management_form as form %} {% include 'bootstrap3/uni_form.html' %} {% endwith %} {% for form in formset %}
    {% include 'bootstrap3/uni_form.html' %}
    {% endfor %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/whole_uni_form.html000066400000000000000000000011741221066745500301430ustar00rootroot00000000000000{% load crispy_forms_utils %} {% specialspaceless %} {% if form_tag %}
    {% endif %} {% if form_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %} {% include "bootstrap3/display_form.html" %} {% if inputs %}
    {% for input in inputs %} {% include "bootstrap3/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if form_tag %}
    {% endif %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/bootstrap3/whole_uni_formset.html000066400000000000000000000015211221066745500306530ustar00rootroot00000000000000{% load crispy_forms_tags %} {% load crispy_forms_utils %} {% specialspaceless %} {% if formset_tag %}
    {% endif %} {% if formset_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %}
    {{ formset.management_form|crispy }}
    {% include "bootstrap3/errors_formset.html" %} {% for form in formset %} {% include "bootstrap3/display_form.html" %} {% endfor %} {% if inputs %}
    {% for input in inputs %} {% include "bootstrap3/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if formset_tag %}
    {% endif %} {% endspecialspaceless %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/000077500000000000000000000000001221066745500237545ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/betterform.html000066400000000000000000000012321221066745500270110ustar00rootroot00000000000000{% for fieldset in form.fieldsets %}
    {% if fieldset.legend %} {{ fieldset.legend }} {% endif %} {% if fieldset.description %}

    {{ fieldset.description }}

    {% endif %} {% for field in fieldset %} {% if field.is_hidden %} {{ field }} {% else %} {% include "uni_form/field.html" %} {% endif %} {% endfor %} {% if not forloop.last or not fieldset_open %}
    {% endif %} {% endfor %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/display_form.html000066400000000000000000000003161221066745500273320ustar00rootroot00000000000000{% if form.form_html %} {% if form_show_errors %} {% include "uni_form/errors.html" %} {% endif %} {{ form.form_html }} {% else %} {% include "uni_form/uni_form.html" %} {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/errors.html000066400000000000000000000003741221066745500261620ustar00rootroot00000000000000{% if form.errors and form.non_field_errors %}
    {% if form_error_title %}

    {{ form_error_title }}

    {% endif %}
      {{ form.non_field_errors|unordered_list }}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/errors_formset.html000066400000000000000000000003671221066745500277230ustar00rootroot00000000000000{% if formset.non_form_errors %}
    {% if formset_error_title %}

    {{ formset_error_title }}

    {% endif %}
      {{ formset.non_form_errors|unordered_list }}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/field.html000066400000000000000000000024271221066745500257320ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %}
    {% if form_show_errors %} {% for error in field.errors %}

    {{ error }}

    {% endfor %} {% endif %} {% if field.label %} {% if field|is_checkbox %} {% crispy_field field %} {% endif %} {% endif %} {% if not field|is_checkbox %} {% crispy_field field %} {% endif %} {% if field.help_text %}
    {{ field.help_text|safe }}
    {% endif %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/field.strict.html000066400000000000000000000022061221066745500272340ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %}
    {% for error in field.errors %}

    {{ error }}

    {% endfor %} {% if field|is_checkbox %} {% crispy_field field %} {% endif %} {% if field.label %} {% endif %} {% if not field|is_checkbox %} {% crispy_field field %} {% endif %} {% if field.help_text %}

    {{ field.help_text|safe }}

    {% endif %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/layout/000077500000000000000000000000001221066745500252715ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/layout/baseinput.html000066400000000000000000000006541221066745500301560ustar00rootroot00000000000000 django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/layout/buttonholder.html000066400000000000000000000003241221066745500306670ustar00rootroot00000000000000
    {{ fields_output|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/layout/div.html000066400000000000000000000002661221066745500267450ustar00rootroot00000000000000
    {{ fields|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/layout/fieldset.html000066400000000000000000000004731221066745500277620ustar00rootroot00000000000000
    {% if legend %}{{ legend|safe }}{% endif %} {{ fields|safe }}
    django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/layout/multifield.html000066400000000000000000000020121221066745500303100ustar00rootroot00000000000000
    {% if form_show_errors %} {% for field in multifield.bound_fields %} {% if field.errors %} {% for error in field.errors %}

    {{ error }}

    {% endfor %} {% endif %} {% endfor %} {% endif %} {% if multifield.label_html %}

    {{ multifield.label_html|safe }}

    {% endif %}
    {{ fields_output|safe }}
    {% for field in multifield.bound_fields %} {% if field.help_text %}

    {{ field.help_text|safe }}

    {% endif %} {% endfor %}
    django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/multifield.html000066400000000000000000000012761221066745500270060ustar00rootroot00000000000000{% load crispy_forms_field %} {% if field.is_hidden %} {{ field }} {% else %}
    {% if field.label %} {% endif %} {% crispy_field field %} {% if field.help_text %}
    {{ field.help_text|safe }}
    {% endif %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/uni_form.html000066400000000000000000000005311221066745500264570ustar00rootroot00000000000000{% if form_show_errors %} {% include "uni_form/errors.html" %} {% endif %} {% if form_style == "" or form_style %}
    {% endif %} {% for field in form %} {% include "uni_form/field.html" %} {% endfor %} {% if form_style == "" or form_style %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/uni_formset.html000066400000000000000000000003421221066745500271730ustar00rootroot00000000000000{% with formset.management_form as form %} {% include 'uni_form/uni_form.html' %} {% endwith %} {% for form in formset %}
    {% include 'uni_form/uni_form.html' %}
    {% endfor %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/whole_uni_form.html000066400000000000000000000010501221066745500276520ustar00rootroot00000000000000{% if form_tag %}
    {% endif %} {% if form_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %} {% include "uni_form/display_form.html" %} {% if inputs %}
    {% for input in inputs %} {% include "uni_form/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if form_tag %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templates/uni_form/whole_uni_formset.html000066400000000000000000000013771221066745500304020ustar00rootroot00000000000000{% load crispy_forms_tags %} {% if formset_tag %}
    {% endif %} {% if formset_method|lower == 'post' and not disable_csrf %} {% csrf_token %} {% endif %}
    {{ formset.management_form|crispy }}
    {% include "uni_form/errors_formset.html" %} {% for form in formset %} {% include "uni_form/display_form.html" %} {% endfor %} {% if inputs %}
    {% for input in inputs %} {% include "uni_form/layout/baseinput.html" %} {% endfor %}
    {% endif %} {% if formset_tag %}
    {% endif %} django-crispy-forms-1.4.0/crispy_forms/templatetags/000077500000000000000000000000001221066745500226325ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templatetags/__init__.py000066400000000000000000000000001221066745500247310ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/templatetags/crispy_forms_field.py000066400000000000000000000117611221066745500270740ustar00rootroot00000000000000try: from itertools import izip except ImportError: izip = zip from django import forms from django import template from django.template import loader, Context from django.conf import settings from crispy_forms.utils import TEMPLATE_PACK register = template.Library() class_converter = { "textinput": "textinput textInput", "fileinput": "fileinput fileUpload", "passwordinput": "textinput textInput", } class_converter.update(getattr(settings, 'CRISPY_CLASS_CONVERTERS', {})) @register.filter def is_checkbox(field): return isinstance(field.field.widget, forms.CheckboxInput) @register.filter def is_password(field): return isinstance(field.field.widget, forms.PasswordInput) @register.filter def is_radioselect(field): return isinstance(field.field.widget, forms.RadioSelect) @register.filter def is_checkboxselectmultiple(field): return isinstance(field.field.widget, forms.CheckboxSelectMultiple) @register.filter def is_file(field): return isinstance(field.field.widget, forms.ClearableFileInput) @register.filter def classes(field): """ Returns CSS classes of a field """ return field.widget.attrs.get('class', None) @register.filter def css_class(field): """ Returns widgets class name in lowercase """ return field.field.widget.__class__.__name__.lower() def pairwise(iterable): "s -> (s0,s1), (s2,s3), (s4, s5), ..." a = iter(iterable) return izip(a, a) class CrispyFieldNode(template.Node): def __init__(self, field, attrs): self.field = field self.attrs = attrs self.html5_required = 'html5_required' def render(self, context): # Nodes are not threadsafe so we must store and look up our instance # variables in the current rendering context first if self not in context.render_context: context.render_context[self] = ( template.Variable(self.field), self.attrs, template.Variable(self.html5_required) ) field, attrs, html5_required = context.render_context[self] field = field.resolve(context) try: html5_required = html5_required.resolve(context) except template.VariableDoesNotExist: html5_required = False widgets = getattr(field.field.widget, 'widgets', [field.field.widget]) if isinstance(attrs, dict): attrs = [attrs] * len(widgets) for widget, attr in zip(widgets, attrs): class_name = widget.__class__.__name__.lower() class_name = class_converter.get(class_name, class_name) css_class = widget.attrs.get('class', '') if css_class: if css_class.find(class_name) == -1: css_class += " %s" % class_name else: css_class = class_name if ( TEMPLATE_PACK == 'bootstrap3' and not is_checkbox(field) and not is_file(field) ): css_class += ' form-control' widget.attrs['class'] = css_class # HTML5 required attribute if html5_required and field.field.required and 'required' not in widget.attrs: if field.field.widget.__class__.__name__ is not 'RadioSelect': widget.attrs['required'] = 'required' for attribute_name, attribute in attr.items(): attribute_name = template.Variable(attribute_name).resolve(context) if attribute_name in widget.attrs: widget.attrs[attribute_name] += " " + template.Variable(attribute).resolve(context) else: widget.attrs[attribute_name] = template.Variable(attribute).resolve(context) return field @register.tag(name="crispy_field") def crispy_field(parser, token): """ {% crispy_field field attrs %} """ token = token.split_contents() field = token.pop(1) attrs = {} # We need to pop tag name, or pairwise would fail token.pop(0) for attribute_name, value in pairwise(token): attrs[attribute_name] = value return CrispyFieldNode(field, attrs) @register.simple_tag() def crispy_addon(field, append="", prepend=""): """ Renders a form field using bootstrap's prepended or appended text:: {% crispy_addon form.my_field prepend="$" append=".00" %} You can also just prepend or append like so {% crispy_addon form.my_field prepend="$" %} {% crispy_addon form.my_field append=".00" %} """ if (field): context = Context({ 'field': field, 'form_show_errors': True }) template = loader.get_template('%s/layout/prepended_appended_text.html' % TEMPLATE_PACK) context['crispy_prepended_text'] = prepend context['crispy_appended_text'] = append if not prepend and not append: raise TypeError("Expected a prepend and/or append argument") return template.render(context) django-crispy-forms-1.4.0/crispy_forms/templatetags/crispy_forms_filters.py000066400000000000000000000066461221066745500274670ustar00rootroot00000000000000# -*- coding: utf-8 -*- from django.conf import settings from django.forms import forms from django.forms.formsets import BaseFormSet from django.template import Context from django.template.loader import get_template from django.utils.functional import memoize from django.utils.safestring import mark_safe from django import template from crispy_forms.exceptions import CrispyError from crispy_forms.utils import flatatt TEMPLATE_PACK = getattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap') DEBUG = getattr(settings, 'DEBUG', False) def uni_formset_template(template_pack=TEMPLATE_PACK): return get_template('%s/uni_formset.html' % template_pack) uni_formset_template = memoize(uni_formset_template, {}, 1) def uni_form_template(template_pack=TEMPLATE_PACK): return get_template('%s/uni_form.html' % template_pack) uni_form_template = memoize(uni_form_template, {}, 1) register = template.Library() @register.filter(name='crispy') def as_crispy_form(form, template_pack=TEMPLATE_PACK, label_class="", field_class=""): """ The original and still very useful way to generate a div elegant form/formset:: {% load crispy_forms_tags %}
    {% csrf_token %} {{ myform|crispy }}
    or, if you want to explicitly set the template pack:: {{ myform|crispy:"bootstrap" }} In ``bootstrap3`` for horizontal forms you can do:: {{ myform|label_class:"col-lg-2",field_class:"col-lg-8" }} """ if isinstance(form, BaseFormSet): template = uni_formset_template(template_pack) c = Context({ 'formset': form, 'form_show_errors': True, 'form_show_labels': True, 'label_class': label_class, 'field_class': field_class, }) else: template = uni_form_template(template_pack) c = Context({ 'form': form, 'form_show_errors': True, 'form_show_labels': True, 'label_class': label_class, 'field_class': field_class, }) return template.render(c) @register.filter(name='as_crispy_errors') def as_crispy_errors(form, template_pack=TEMPLATE_PACK): """ Renders only form errors the same way as django-crispy-forms:: {% load crispy_forms_tags %} {{ form|as_crispy_errors }} or:: {{ form|as_crispy_errors:"bootstrap" }} """ if isinstance(form, BaseFormSet): template = get_template('%s/errors_formset.html' % template_pack) c = Context({'formset': form}) else: template = get_template('%s/errors.html' % template_pack) c = Context({'form': form}) return template.render(c) @register.filter(name='as_crispy_field') def as_crispy_field(field, template_pack=TEMPLATE_PACK): """ Renders a form field like a django-crispy-forms field:: {% load crispy_forms_tags %} {{ form.field|as_crispy_field }} or:: {{ form.field|as_crispy_field:"bootstrap" }} """ if not isinstance(field, forms.BoundField) and DEBUG: raise CrispyError('|as_crispy_field got passed an invalid or inexistent field') template = get_template('%s/field.html' % template_pack) c = Context({'field': field, 'form_show_errors': True, 'form_show_labels': True}) return template.render(c) @register.filter(name='flatatt') def flatatt_filter(attrs): return mark_safe(flatatt(attrs)) django-crispy-forms-1.4.0/crispy_forms/templatetags/crispy_forms_tags.py000066400000000000000000000250361221066745500267470ustar00rootroot00000000000000# -*- coding: utf-8 -*- from copy import copy from django.conf import settings from django.forms.formsets import BaseFormSet from django.template import Context from django.template.loader import get_template from django.utils.functional import memoize from django import template from crispy_forms.helper import FormHelper register = template.Library() # We import the filters, so they are available when doing load crispy_forms_tags from crispy_forms.templatetags.crispy_forms_filters import * TEMPLATE_PACK = getattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap') ALLOWED_TEMPLATE_PACKS = getattr(settings, 'CRISPY_ALLOWED_TEMPLATE_PACKS', ('bootstrap', 'uni_form')) class ForLoopSimulator(object): """ Simulates a forloop tag, precisely:: {% for form in formset.forms %} If `{% crispy %}` is rendering a formset with a helper, We inject a `ForLoopSimulator` object in the context as `forloop` so that formset forms can do things like:: Fieldset("Item {{ forloop.counter }}", [...]) HTML("{% if forloop.first %}First form text{% endif %}" """ def __init__(self, formset): self.len_values = len(formset.forms) # Shortcuts for current loop iteration number. self.counter = 1 self.counter0 = 0 # Reverse counter iteration numbers. self.revcounter = self.len_values self.revcounter0 = self.len_values - 1 # Boolean values designating first and last times through loop. self.first = True self.last = (0 == self.len_values - 1) def iterate(self): """ Updates values as if we had iterated over the for """ self.counter += 1 self.counter0 += 1 self.revcounter -= 1 self.revcounter0 -= 1 self.first = False self.last = (self.revcounter0 == self.len_values - 1) def copy_context(context): """ Copies a `Context` variable. It uses `Context.__copy__` if available (introduced in Django 1.3) or copy otherwise. """ if hasattr(context, "__copy__"): return context.__copy__() duplicate = copy(context) duplicate.dicts = context.dicts[:] return duplicate class BasicNode(template.Node): """ Basic Node object that we can rely on for Node objects in normal template tags. I created this because most of the tags we'll be using will need both the form object and the helper string. This handles both the form object and parses out the helper string into attributes that templates can easily handle. """ def __init__(self, form, helper, template_pack=TEMPLATE_PACK): self.form = form if helper is not None: self.helper = helper else: self.helper = None self.template_pack = template_pack def get_render(self, context): """ Returns a `Context` object with all the necesarry stuff for rendering the form :param context: `django.template.Context` variable holding the context for the node `self.form` and `self.helper` are resolved into real Python objects resolving them from the `context`. The `actual_form` can be a form or a formset. If it's a formset `is_formset` is set to True. If the helper has a layout we use it, for rendering the form or the formset's forms. """ # Nodes are not thread safe in multithreaded environments # https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#thread-safety-considerations if self not in context.render_context: context.render_context[self] = ( template.Variable(self.form), template.Variable(self.helper) if self.helper else None ) form, helper = context.render_context[self] actual_form = form.resolve(context) if self.helper is not None: helper = helper.resolve(context) else: # If the user names the helper within the form `helper` (standard), we use it # This allows us to have simplified tag syntax: {% crispy form %} helper = FormHelper() if not hasattr(actual_form, 'helper') else actual_form.helper self.actual_helper = helper # We get the response dictionary is_formset = isinstance(actual_form, BaseFormSet) response_dict = self.get_response_dict(helper, context, is_formset) node_context = copy_context(context) node_context.update(response_dict) # If we have a helper's layout we use it, for the form or the formset's forms if helper and helper.layout: if not is_formset: actual_form.form_html = helper.render_layout(actual_form, node_context, template_pack=self.template_pack) else: forloop = ForLoopSimulator(actual_form) helper.render_hidden_fields = True for form in actual_form: node_context.update({'forloop': forloop}) form.form_html = helper.render_layout(form, node_context, template_pack=self.template_pack) forloop.iterate() if is_formset: response_dict.update({'formset': actual_form}) else: response_dict.update({'form': actual_form}) return Context(response_dict) def get_response_dict(self, helper, context, is_formset): """ Returns a dictionary with all the parameters necessary to render the form/formset in a template. :param attrs: Dictionary with the helper's attributes used for rendering the form/formset :param context: `django.template.Context` for the node :param is_formset: Boolean value. If set to True, indicates we are working with a formset. """ if not isinstance(helper, FormHelper): raise TypeError('helper object provided to {% crispy %} tag must be a crispy.helper.FormHelper object.') attrs = helper.get_attributes(template_pack=self.template_pack) form_type = "form" if is_formset: form_type = "formset" # We take form/formset parameters from attrs if they are set, otherwise we use defaults response_dict = { 'template_pack': settings.CRISPY_TEMPLATE_PACK, '%s_action' % form_type: attrs['attrs'].get("action", ''), '%s_method' % form_type: attrs.get("form_method", 'post'), '%s_tag' % form_type: attrs.get("form_tag", True), '%s_class' % form_type: attrs['attrs'].get("class", ''), '%s_id' % form_type: attrs['attrs'].get("id", ""), '%s_style' % form_type: attrs.get("form_style", None), 'form_error_title': attrs.get("form_error_title", None), 'formset_error_title': attrs.get("formset_error_title", None), 'form_show_errors': attrs.get("form_show_errors", True), 'help_text_inline': attrs.get("help_text_inline", False), 'html5_required': attrs.get("html5_required", False), 'form_show_labels': attrs.get("form_show_labels", True), 'disable_csrf': attrs.get("disable_csrf", False), 'inputs': attrs.get('inputs', []), 'is_formset': is_formset, '%s_attrs' % form_type: attrs.get('attrs', ''), 'flat_attrs': attrs.get('flat_attrs', ''), 'error_text_inline': attrs.get('error_text_inline', True), 'label_class': attrs.get('label_class', ''), 'label_size': attrs.get('label_size', 0), 'field_class': attrs.get('field_class', ''), } # Handles custom attributes added to helpers for attribute_name, value in attrs.items(): if attribute_name not in response_dict: response_dict[attribute_name] = value if 'csrf_token' in context: response_dict['csrf_token'] = context['csrf_token'] return response_dict def whole_uni_formset_template(template_pack=TEMPLATE_PACK): return get_template('%s/whole_uni_formset.html' % template_pack) whole_uni_formset_template = memoize(whole_uni_formset_template, {}, 1) def whole_uni_form_template(template_pack=TEMPLATE_PACK): return get_template('%s/whole_uni_form.html' % template_pack) whole_uni_form_template = memoize(whole_uni_form_template, {}, 1) class CrispyFormNode(BasicNode): def render(self, context): c = self.get_render(context) if self.actual_helper is not None and getattr(self.actual_helper, 'template', False): template = get_template(self.actual_helper.template) else: if c['is_formset']: template = whole_uni_formset_template(self.template_pack) else: template = whole_uni_form_template(self.template_pack) return template.render(c) # {% crispy %} tag @register.tag(name="crispy") def do_uni_form(parser, token): """ You need to pass in at least the form/formset object, and can also pass in the optional `crispy_forms.helpers.FormHelper` object. helper (optional): A `crispy_forms.helper.FormHelper` object. Usage:: {% include crispy_tags %} {% crispy form form.helper %} You can also provide the template pack as the third argument:: {% crispy form form.helper 'bootstrap' %} If the `FormHelper` attribute is named `helper` you can simply do:: {% crispy form %} {% crispy form 'bootstrap' %} """ token = token.split_contents() form = token.pop(1) try: helper = token.pop(1) except IndexError: helper = None try: # {% crispy form helper 'bootstrap' %} template_pack = token.pop(1) if not (template_pack[0] == template_pack[-1] and template_pack[0] in ('"', "'")): raise template.TemplateSyntaxError("crispy tag's template_pack argument should be in quotes") template_pack = template_pack[1:-1] if template_pack not in ALLOWED_TEMPLATE_PACKS: raise template.TemplateSyntaxError("crispy tag's template_pack argument should be \ in " + str(ALLOWED_TEMPLATE_PACKS)) except IndexError: # {% crispy form 'bootstrap' %} # ('"'bootstrap'"', '"'uni_form'"','"'"bootstrap'"'", '"'"uni_form"'") if ( helper in ['"%s"' % x for x in ALLOWED_TEMPLATE_PACKS] + \ ["'%s'" % x for x in ALLOWED_TEMPLATE_PACKS] ): template_pack = helper[1:-1] helper = None # {% crispy form helper %} OR {% crispy form %} else: template_pack = TEMPLATE_PACK return CrispyFormNode(form, helper, template_pack=template_pack) django-crispy-forms-1.4.0/crispy_forms/templatetags/crispy_forms_utils.py000066400000000000000000000042031221066745500271420ustar00rootroot00000000000000# -*- coding: utf-8 -*- import re from django import template from django.conf import settings try: # Django < 1.4 from django.utils.encoding import force_unicode as force_text except ImportError: from django.utils.encoding import force_text from django.utils.functional import allow_lazy from crispy_forms.compatibility import text_type register = template.Library() TEMPLATE_PACK = getattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap') def selectively_remove_spaces_between_tags(value, template_pack, form_class): if ( 'bootstrap' in template_pack and 'form-inline' in form_class ): # Bootstrap inline forms rely on spaces separating inputs, really html = re.sub(r'>\s+<', '> <', force_text(value)) html = re.sub(r'<', ' <', force_text(html)) return re.sub(r'/><', r'/> <', force_text(html)) else: html = re.sub(r'>\s+<', '><', force_text(value)) html = re.sub(r'<', ' <', force_text(html)) return re.sub(r'/><', r'/> <', force_text(html)) return value selectively_remove_spaces_between_tags = allow_lazy( selectively_remove_spaces_between_tags, text_type ) class SpecialSpacelessNode(template.Node): def __init__(self, nodelist): self.nodelist = nodelist def render(self, context): try: template_pack = template.Variable('template_pack').resolve(context) except: template_pack = TEMPLATE_PACK try: form_attrs = template.Variable('form_attrs').resolve(context) except: form_attrs = {} return selectively_remove_spaces_between_tags( self.nodelist.render(context).strip(), template_pack, form_attrs.get('class', ''), ) @register.tag def specialspaceless(parser, token): """ Removes whitespace between HTML tags, and introduces a whitespace after buttons an inputs, necessary for Bootstrap to place them correctly in the layout. """ nodelist = parser.parse(('endspecialspaceless',)) parser.delete_first_token() return SpecialSpacelessNode(nodelist) django-crispy-forms-1.4.0/crispy_forms/tests/000077500000000000000000000000001221066745500213025ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/tests/__init__.py000066400000000000000000000002271221066745500234140ustar00rootroot00000000000000from .test_tags import * from .test_layout import * from .test_layout_objects import * from .test_form_helper import * from .test_dynamic_api import * django-crispy-forms-1.4.0/crispy_forms/tests/base.py000066400000000000000000000023261221066745500225710ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os from django.conf import settings from django.template import loader from django.test import TestCase from crispy_forms.tests.utils import override_settings class CrispyTestCase(TestCase): def setUp(self): template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')] template_dirs = template_dirs + list(settings.TEMPLATE_DIRS) template_loaders = ['django.template.loaders.filesystem.Loader'] template_loaders = template_loaders + list(settings.TEMPLATE_LOADERS) # ensuring test templates directory is loaded first self.__overriden_settings = override_settings(**{ 'TEMPLATE_LOADERS': template_loaders, 'TEMPLATE_DIRS': template_dirs, }) self.__overriden_settings.enable() # resetting template loaders cache self.__template_source_loaders = loader.template_source_loaders loader.template_source_loaders = None def tearDown(self): loader.template_source_loaders = self.__template_source_loaders self.__overriden_settings.disable() @property def current_template_pack(self): return getattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap') django-crispy-forms-1.4.0/crispy_forms/tests/forms.py000066400000000000000000000064661221066745500230160ustar00rootroot00000000000000from django import forms from django.db import models from crispy_forms.helper import FormHelper class TestForm(forms.Form): is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput()) email = forms.EmailField(label="email", max_length=30, required=True, widget=forms.TextInput(), help_text="Insert your email") password1 = forms.CharField(label="password", max_length=30, required=True, widget=forms.PasswordInput()) password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput()) first_name = forms.CharField(label="first name", max_length=5, required=True, widget=forms.TextInput()) last_name = forms.CharField(label="last name", max_length=5, required=True, widget=forms.TextInput()) datetime_field = forms.DateTimeField(label="date time", widget=forms.SplitDateTimeWidget()) def clean(self): super(TestForm, self).clean() password1 = self.cleaned_data.get('password1', None) password2 = self.cleaned_data.get('password2', None) if not password1 and not password2 or password1 != password2: raise forms.ValidationError("Passwords dont match") return self.cleaned_data class TestForm2(TestForm): def __init__(self, *args, **kwargs): super(TestForm2, self).__init__(*args, **kwargs) self.helper = FormHelper(self) class CheckboxesTestForm(forms.Form): checkboxes = forms.MultipleChoiceField( choices = ( (1, "Option one"), (2, "Option two"), (3, "Option three") ), initial = (1,), widget = forms.CheckboxSelectMultiple, ) alphacheckboxes = forms.MultipleChoiceField( choices = ( ('option_one', "Option one"), ('option_two', "Option two"), ('option_three', "Option three") ), initial = ('option_two', 'option_three'), widget = forms.CheckboxSelectMultiple, ) numeric_multiple_checkboxes = forms.MultipleChoiceField( choices = ( (1, "Option one"), (2, "Option two"), (3, "Option three") ), initial = (1, 2), widget = forms.CheckboxSelectMultiple, ) inline_radios = forms.ChoiceField( choices = ( ('option_one', "Option one"), ('option_two', "Option two"), ), widget = forms.RadioSelect, initial = 'option_two', ) class CrispyTestModel(models.Model): email = models.CharField(max_length=20) password = models.CharField(max_length=20) class TestForm3(forms.ModelForm): class Meta: model = CrispyTestModel fields = ['email', 'password'] exclude = ['password'] def __init__(self, *args, **kwargs): super(TestForm3, self).__init__(*args, **kwargs) self.helper = FormHelper(self) class TestForm4(forms.ModelForm): class Meta: model = CrispyTestModel class TestForm5(forms.Form): choices = [ (1, 1), (2, 2), (1000, 1000), ] checkbox_select_multiple = forms.MultipleChoiceField( widget=forms.CheckboxSelectMultiple, choices=choices ) radio_select = forms.ChoiceField( widget=forms.RadioSelect, choices=choices ) pk = forms.IntegerField() django-crispy-forms-1.4.0/crispy_forms/tests/runtests.py000077500000000000000000000003641221066745500235510ustar00rootroot00000000000000#!/usr/bin/env python import os import sys cmds = [ 'python runtests_bootstrap.py', 'python runtests_bootstrap3.py', 'python runtests_uniform.py', ] for cmd in cmds: retval = os.system(cmd) if retval: sys.exit(1) django-crispy-forms-1.4.0/crispy_forms/tests/runtests_bootstrap.py000077500000000000000000000016021221066745500256420ustar00rootroot00000000000000#!/usr/bin/env python import os, sys os.environ['DJANGO_SETTINGS_MODULE'] = 'test_settings' parent = os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) sys.path.insert(0, parent) from django.test.simple import DjangoTestSuiteRunner from django.conf import settings settings.CRISPY_TEMPLATE_PACK = 'bootstrap' def runtests(): return DjangoTestSuiteRunner(failfast=False).run_tests([ 'crispy_forms.TestBasicFunctionalityTags', 'crispy_forms.TestFormHelper', 'crispy_forms.TestBootstrapFormHelper', 'crispy_forms.TestFormLayout', 'crispy_forms.TestBootstrapFormLayout', 'crispy_forms.TestLayoutObjects', 'crispy_forms.TestBootstrapLayoutObjects', 'crispy_forms.TestDynamicLayouts' ], verbosity=1, interactive=True) if __name__ == '__main__': if runtests(): sys.exit(1) django-crispy-forms-1.4.0/crispy_forms/tests/runtests_bootstrap3.py000077500000000000000000000016641221066745500257350ustar00rootroot00000000000000#!/usr/bin/env python import os, sys os.environ['DJANGO_SETTINGS_MODULE'] = 'test_settings' parent = os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) sys.path.insert(0, parent) from django.test.simple import DjangoTestSuiteRunner from django.conf import settings settings.CRISPY_TEMPLATE_PACK = 'bootstrap3' def runtests(): return DjangoTestSuiteRunner(failfast=False).run_tests([ 'crispy_forms.TestBasicFunctionalityTags', 'crispy_forms.TestFormHelper', 'crispy_forms.TestBootstrapFormHelper', 'crispy_forms.TestFormLayout', 'crispy_forms.TestBootstrapFormLayout', 'crispy_forms.TestBootstrap3FormLayout', 'crispy_forms.TestLayoutObjects', 'crispy_forms.TestBootstrapLayoutObjects', 'crispy_forms.TestDynamicLayouts' ], verbosity=1, interactive=True) if __name__ == '__main__': if runtests(): sys.exit(1) django-crispy-forms-1.4.0/crispy_forms/tests/runtests_uniform.py000077500000000000000000000013561221066745500253120ustar00rootroot00000000000000#!/usr/bin/env python import os, sys os.environ['DJANGO_SETTINGS_MODULE'] = 'test_settings' parent = os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) sys.path.insert(0, parent) from django.test.simple import DjangoTestSuiteRunner from django.conf import settings settings.CRISPY_TEMPLATE_PACK = 'uni_form' def runtests(): return DjangoTestSuiteRunner(failfast=False).run_tests([ 'crispy_forms.TestBasicFunctionalityTags', 'crispy_forms.TestFormHelper', 'crispy_forms.TestFormLayout', 'crispy_forms.TestLayoutObjects', 'crispy_forms.TestDynamicLayouts' ], verbosity=1, interactive=True) if __name__ == '__main__': if runtests(): sys.exit(1) django-crispy-forms-1.4.0/crispy_forms/tests/templates/000077500000000000000000000000001221066745500233005ustar00rootroot00000000000000django-crispy-forms-1.4.0/crispy_forms/tests/templates/crispy_render_template.html000066400000000000000000000000601221066745500307250ustar00rootroot00000000000000{% load crispy_forms_tags %} {% crispy form %} django-crispy-forms-1.4.0/crispy_forms/tests/templates/custom_field_template.html000066400000000000000000000001031221066745500305300ustar00rootroot00000000000000

    Special custom field

    {% include 'bootstrap/field.html' %} django-crispy-forms-1.4.0/crispy_forms/tests/templates/custom_form_template.html000066400000000000000000000001131221066745500304110ustar00rootroot00000000000000

    Special custom form

    {% include "bootstrap/whole_uni_form.html" %} django-crispy-forms-1.4.0/crispy_forms/tests/test_dynamic_api.py000066400000000000000000000412761221066745500252020ustar00rootroot00000000000000# -*- coding: utf-8 -*- from django import forms from .base import CrispyTestCase from crispy_forms.compatibility import string_types from crispy_forms.exceptions import DynamicError from crispy_forms.helper import FormHelper, FormHelpersException from crispy_forms.layout import Submit from crispy_forms.layout import ( Layout, Fieldset, MultiField, HTML, Div, Field ) from crispy_forms.bootstrap import AppendedText from crispy_forms.tests.forms import TestForm class TestDynamicLayouts(CrispyTestCase): def setUp(self): super(TestDynamicLayouts, self).setUp() self.advanced_layout = Layout( Div( Div(Div('email')), Div(Field('password1')), Submit("save", "save"), Fieldset( "legend", 'first_name', HTML("extra text"), ), Layout( "password2", ), ), 'last_name', ) def test_wrap_all_fields(self): helper = FormHelper() layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper.all().wrap(Field, css_class="test-class") for field in layout.fields: self.assertTrue(isinstance(field, Field)) self.assertEqual(field.attrs['class'], "test-class") self.assertEqual(layout[0][0], 'email') self.assertEqual(layout[1][0], 'password1') self.assertEqual(layout[2][0], 'password2') def test_wrap_selected_fields(self): helper = FormHelper() layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper[1:3].wrap(Field, css_class="test-class") self.assertFalse(isinstance(layout.fields[0], Field)) self.assertTrue(isinstance(layout.fields[1], Field)) self.assertTrue(isinstance(layout.fields[2], Field)) helper[0].wrap(Fieldset, 'legend', css_class="test-class") self.assertTrue(isinstance(layout[0], Fieldset)) self.assertEqual(layout[0].legend, 'legend') self.assertEqual(layout[0][0], 'email') def test_wrap_together_with_slices(self): helper = FormHelper() layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper[1:3].wrap_together(Field, css_class="test-class") self.assertEqual(layout.fields[0], 'email') self.assertTrue(isinstance(layout.fields[1], Field)) self.assertEqual(layout.fields[1][0], 'password1') self.assertEqual(layout.fields[1][1], 'password2') layout = Layout( Div('email'), 'password1', 'password2', ) helper.layout = layout helper[0:3].wrap_together(Field, css_class="test-class") self.assertTrue(isinstance(layout.fields[0], Field)) self.assertTrue(isinstance(layout.fields[0][0], Div)) self.assertEqual(layout.fields[0][0][0], 'email') self.assertEqual(layout.fields[0][1], 'password1') self.assertEqual(layout.fields[0][2], 'password2') layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper[0].wrap_together(Field, css_class="test-class") self.assertTrue(isinstance(layout.fields[0], Field)) self.assertEqual(layout.fields[1], 'password1') self.assertEqual(layout.fields[2], 'password2') layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper[0].wrap_together(Fieldset, "legend", css_class="test-class") self.assertTrue(isinstance(layout.fields[0], Fieldset)) self.assertEqual(layout.fields[0].legend, 'legend') self.assertEqual(layout.fields[1], 'password1') self.assertEqual(layout.fields[2], 'password2') def test_wrap_together_partial_slices(self): helper = FormHelper() layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper[:2].wrap_together(Field, css_class="test-class") self.assertTrue(isinstance(layout.fields[0], Field)) self.assertEqual(layout.fields[1], 'password2') self.assertEqual(layout.fields[0][0], 'email') self.assertEqual(layout.fields[0][1], 'password1') helper = FormHelper() layout = Layout( 'email', 'password1', 'password2', ) helper.layout = layout helper[1:].wrap_together(Field, css_class="test-class") self.assertEqual(layout.fields[0], 'email') self.assertTrue(isinstance(layout.fields[1], Field)) self.assertEqual(layout.fields[1][0], 'password1') self.assertEqual(layout.fields[1][1], 'password2') def test_update_attributes(self): helper = FormHelper() helper.layout = Layout( 'email', Field('password1'), 'password2', ) helper['password1'].update_attributes(readonly=True) self.assertTrue('readonly' in helper.layout[1].attrs) def test_update_attributes_and_wrap_once(self): helper = FormHelper() layout = Layout( 'email', Field('password1'), 'password2', ) helper.layout = layout helper.filter(Field).update_attributes(readonly=True) self.assertTrue(isinstance(layout[1], Field)) self.assertEqual(layout[1].attrs, {'readonly': True}) layout = Layout( 'email', Div(Field('password1')), 'password2', ) helper.layout = layout helper.filter(Field, max_level=2).update_attributes(readonly=True) self.assertTrue(isinstance(layout[1][0], Field)) self.assertEqual(layout[1][0].attrs, {'readonly': True}) layout = Layout( 'email', Div(Field('password1')), 'password2', ) helper.layout = layout helper.filter(string_types, greedy=True).wrap_once(Field) helper.filter(Field, greedy=True).update_attributes(readonly=True) self.assertTrue(isinstance(layout[0], Field)) self.assertTrue(isinstance(layout[1][0], Field)) self.assertTrue(isinstance(layout[1][0][0], string_types)) self.assertTrue(isinstance(layout[2], Field)) self.assertEqual(layout[1][0].attrs, {'readonly': True}) self.assertEqual(layout[0].attrs, {'readonly': True}) self.assertEqual(layout[2].attrs, {'readonly': True}) def test_get_layout_objects(self): layout_1 = Layout( Div() ) self.assertEqual(layout_1.get_layout_objects(Div), [ [[0], 'div'] ]) layout_2 = Layout( Div( Div( Div('email') ), Div('password1'), 'password2' ) ) self.assertEqual(layout_2.get_layout_objects(Div), [ [[0], 'div'] ]) self.assertEqual(layout_2.get_layout_objects(Div, max_level=1), [ [[0], 'div'], [[0, 0], 'div'], [[0, 1], 'div'] ]) self.assertEqual(layout_2.get_layout_objects(Div, max_level=2), [ [[0], 'div'], [[0, 0], 'div'], [[0, 0, 0], 'div'], [[0, 1], 'div'] ]) layout_3 = Layout( 'email', Div('password1'), 'password2', ) self.assertEqual(layout_3.get_layout_objects(string_types, max_level=2), [ [[0], 'email'], [[1, 0], 'password1'], [[2], 'password2'] ]) layout_4 = Layout( Div( Div('field_name'), 'field_name2', ), Div('password'), 'extra_field' ) self.assertEqual(layout_4.get_layout_objects(Div), [ [[0], 'div'], [[1], 'div'] ]) self.assertEqual(layout_4.get_layout_objects(Div, max_level=1), [ [[0], 'div'], [[0, 0], 'div'], [[1], 'div'] ]) def test_filter(self): helper = FormHelper() helper.layout = Layout( Div( MultiField('field_name'), 'field_name2', ), Div('password'), 'extra_field' ) self.assertEqual(helper.filter(Div, MultiField).slice, [ [[0], 'div'], [[1], 'div'] ]) self.assertEqual(helper.filter(Div, MultiField, max_level=1).slice, [ [[0], 'div'], [[0, 0], 'multifield'], [[1], 'div'] ]) self.assertEqual(helper.filter(MultiField, max_level=1).slice, [ [[0, 0], 'multifield'] ]) def test_filter_and_wrap(self): helper = FormHelper() layout = Layout( 'email', Div('password1'), 'password2', ) helper.layout = layout helper.filter(string_types).wrap(Field, css_class="test-class") self.assertTrue(isinstance(layout.fields[0], Field)) self.assertTrue(isinstance(layout.fields[1], Div)) self.assertTrue(isinstance(layout.fields[2], Field)) self.assertEqual(layout[2][0], 'password2') # Wrapping a div in a div helper.filter(Div).wrap(Div, css_class="test-class") self.assertTrue(isinstance(layout.fields[1], Div)) self.assertTrue(isinstance(layout.fields[1].fields[0], Div)) self.assertEqual(layout[1][0][0], 'password1') def test_filter_and_wrap_side_effects(self): helper = FormHelper() layout = Layout( Div( 'extra_field', Div('password1'), ), ) helper.layout = layout self.assertRaises(DynamicError, lambda: helper.filter(Div, max_level=2).wrap(Div, css_class="test-class")) def test_get_field_names(self): layout_1 = Div( 'field_name' ) self.assertEqual(layout_1.get_field_names(), [ [[0], 'field_name'] ]) layout_2 = Div( Div('field_name') ) self.assertEqual(layout_2.get_field_names(), [ [[0, 0], 'field_name'] ]) layout_3 = Div( Div('field_name'), 'password' ) self.assertEqual(layout_3.get_field_names(), [ [[0, 0], 'field_name'], [[1], 'password'] ]) layout_4 = Div( Div( Div('field_name'), 'field_name2', ), Div('password'), 'extra_field' ) self.assertEqual(layout_4.get_field_names(), [ [[0, 0, 0], 'field_name'], [[0, 1], 'field_name2'], [[1, 0], 'password'], [[2], 'extra_field'] ]) layout_5 = Div( Div( 'field_name', 'field_name2', ), 'extra_field' ) self.assertEqual(layout_5.get_field_names(), [ [[0, 0], 'field_name'], [[0, 1], 'field_name2'], [[1], 'extra_field'], ]) def test_layout_get_field_names(self): layout_1 = Layout( Div('field_name'), 'password' ) self.assertEqual(layout_1.get_field_names(), [ [[0, 0], 'field_name'], [[1], 'password'], ]) layout_2 = Layout( Div('field_name'), 'password', Fieldset('legend', 'extra_field') ) self.assertEqual(layout_2.get_field_names(), [ [[0, 0], 'field_name'], [[1], 'password'], [[2, 0], 'extra_field'], ]) layout_3 = Layout( Div( Div( Div('email') ), Div('password1'), 'password2' ) ) self.assertEqual(layout_3.get_field_names(), [ [[0, 0, 0, 0], 'email'], [[0, 1, 0], 'password1'], [[0, 2], 'password2'], ]) def test_filter_by_widget(self): form = TestForm() form.helper = FormHelper(form) form.helper.layout = self.advanced_layout self.assertEqual(form.helper.filter_by_widget(forms.PasswordInput).slice, [ [[0, 1, 0, 0], 'password1'], [[0, 4, 0], 'password2'], ]) def test_exclude_by_widget(self): form = TestForm() form.helper = FormHelper(form) form.helper.layout = self.advanced_layout self.assertEqual(form.helper.exclude_by_widget(forms.PasswordInput).slice, [ [[0, 0, 0, 0], 'email'], [[0, 3, 0], 'first_name'], [[1], 'last_name'], ]) def test_exclude_by_widget_and_wrap(self): form = TestForm() form.helper = FormHelper(form) form.helper.layout = self.advanced_layout form.helper.exclude_by_widget(forms.PasswordInput).wrap(Field, css_class='hero') # Check wrapped fields self.assertTrue(isinstance(form.helper.layout[0][0][0][0], Field)) self.assertTrue(isinstance(form.helper.layout[0][3][0], Field)) self.assertTrue(isinstance(form.helper.layout[1], Field)) # Check others stay the same self.assertTrue(isinstance(form.helper.layout[0][3][1], HTML)) self.assertTrue(isinstance(form.helper.layout[0][1][0][0], string_types)) self.assertTrue(isinstance(form.helper.layout[0][4][0], string_types)) def test_all_without_layout(self): form = TestForm() form.helper = FormHelper() self.assertRaises(FormHelpersException, lambda: form.helper.all().wrap(Div)) def test_filter_by_widget_without_form(self): form = TestForm() form.helper = FormHelper() form.helper.layout = self.advanced_layout self.assertRaises(FormHelpersException, lambda: form.helper.filter_by_widget(forms.PasswordInput)) def test_formhelper__getitem__(self): helper = FormHelper() layout = Layout( Div('email'), 'password1', ) helper.layout = layout helper['email'].wrap(Field, css_class='hero') self.assertTrue(isinstance(layout[0][0], Field)) self.assertEqual(layout[0][0][0], 'email') helper = FormHelper() helper.layout = Layout('password1') helper['password1'].wrap(AppendedText, "extra") self.assertTrue(isinstance(helper.layout[0], AppendedText)) self.assertEqual(helper.layout[0][0], 'password1') self.assertEqual(helper.layout[0].text, 'extra') def test_formhelper__setitem__(self): helper = FormHelper() layout = Layout( 'first_field', Div('email') ) helper.layout = layout helper[0] = 'replaced' self.assertEqual(layout[0], 'replaced') def test_formhelper__delitem__and__len__(self): helper = FormHelper() layout = Layout( 'first_field', Div('email') ) helper.layout = layout del helper[0] self.assertEqual(len(helper), 1) def test__delitem__and__len__layout_object(self): layout = Layout( 'first_field', Div('email') ) del layout[0] self.assertEqual(len(layout), 1) def test__getitem__layout_object(self): layout = Layout( Div( Div( Div('email') ), Div('password1'), 'password2' ) ) self.assertTrue(isinstance(layout[0], Div)) self.assertTrue(isinstance(layout[0][0], Div)) self.assertTrue(isinstance(layout[0][0][0], Div)) self.assertTrue(isinstance(layout[0][1], Div)) self.assertTrue(isinstance(layout[0][1][0], string_types)) self.assertTrue(isinstance(layout[0][2], string_types)) def test__getattr__append_layout_object(self): layout = Layout( Div('email') ) layout.append('password1') self.assertTrue(isinstance(layout[0], Div)) self.assertTrue(isinstance(layout[0][0], string_types)) self.assertTrue(isinstance(layout[1], string_types)) def test__setitem__layout_object(self): layout = Layout( Div('email') ) layout[0][0] = 'password1' self.assertTrue(isinstance(layout[0], Div)) self.assertEqual(layout[0][0], 'password1') django-crispy-forms-1.4.0/crispy_forms/tests/test_form_helper.py000066400000000000000000000463351221066745500252300ustar00rootroot00000000000000# -*- coding: utf-8 -*- import re import django from django import forms from django.conf import settings from django.core.urlresolvers import reverse from django.forms.models import formset_factory from django.middleware.csrf import _get_new_csrf_key from django.template import ( loader, TemplateSyntaxError, Context ) from django.utils.translation import ugettext_lazy as _ from .base import CrispyTestCase from .forms import TestForm from crispy_forms.bootstrap import ( FieldWithButtons, PrependedAppendedText, AppendedText, PrependedText, StrictButton ) from crispy_forms.compatibility import text_type from crispy_forms.helper import FormHelper, FormHelpersException from crispy_forms.layout import ( Layout, Submit, Reset, Hidden, Button, MultiField, ) from crispy_forms.utils import render_crispy_form from crispy_forms.templatetags.crispy_forms_tags import CrispyFormNode class TestFormHelper(CrispyTestCase): urls = 'crispy_forms.tests.urls' def test_inputs(self): form_helper = FormHelper() form_helper.add_input(Submit('my-submit', 'Submit', css_class="button white")) form_helper.add_input(Reset('my-reset', 'Reset')) form_helper.add_input(Hidden('my-hidden', 'Hidden')) form_helper.add_input(Button('my-button', 'Button')) template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy form form_helper %} """) c = Context({'form': TestForm(), 'form_helper': form_helper}) html = template.render(c) self.assertTrue('button white' in html) self.assertTrue('id="submit-id-my-submit"' in html) self.assertTrue('id="reset-id-my-reset"' in html) self.assertTrue('name="my-hidden"' in html) self.assertTrue('id="button-id-my-button"' in html) if self.current_template_pack == 'uni_form': self.assertTrue('submit submitButton' in html) self.assertTrue('reset resetButton' in html) self.assertTrue('class="button"' in html) else: self.assertTrue('class="btn"' in html) self.assertTrue('btn btn-primary' in html) self.assertTrue('btn btn-inverse' in html) self.assertEqual(len(re.findall(r']+> <', html)), 8) def test_invalid_form_method(self): form_helper = FormHelper() try: form_helper.form_method = "superPost" self.fail("Setting an invalid form_method within the helper should raise an Exception") except FormHelpersException: pass def test_form_with_helper_without_layout(self): form_helper = FormHelper() form_helper.form_id = 'this-form-rocks' form_helper.form_class = 'forms-that-rock' form_helper.form_method = 'GET' form_helper.form_action = 'simpleAction' form_helper.form_error_title = 'ERRORS' template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy testForm form_helper %} """) # now we render it, with errors form = TestForm({'password1': 'wargame','password2': 'god'}) form.is_valid() c = Context({'testForm': form, 'form_helper': form_helper}) html = template.render(c) # Lets make sure everything loads right self.assertTrue(html.count('Passwords dont match" in html) # now lets remove the form tag and render it again. All the True items above # should now be false because the form tag is removed. form_helper.form_tag = False html = template.render(c) self.assertFalse('Passwords dont match' in html) self.assertTrue(text_type(_('This field is required.')) in html) self.assertTrue('error' in html) # Now we render without errors form.helper.form_show_errors = False c = Context({'testForm': form}) html = template.render(c) # Ensure errors were not rendered self.assertFalse('
  • Passwords dont match
  • ' in html) self.assertFalse(text_type(_('This field is required.')) in html) self.assertFalse('error' in html) def test_multifield_errors(self): form = TestForm({ 'email': 'invalidemail', 'password1': 'yes', 'password2': 'yes', }) form.helper = FormHelper() form.helper.layout = Layout( MultiField('legend', 'email') ) form.is_valid() form.helper.form_show_errors = True html = render_crispy_form(form) self.assertEqual(html.count('error'), 3) # Reset layout for avoiding side effects form.helper.layout = Layout( MultiField('legend', 'email') ) form.helper.form_show_errors = False html = render_crispy_form(form) self.assertEqual(html.count('error'), 0) def test_html5_required(self): form = TestForm() form.helper = FormHelper() form.helper.html5_required = True html = render_crispy_form(form) # 6 out of 7 fields are required and an extra one for the SplitDateTimeWidget makes 7. self.assertEqual(html.count('required="required"'), 7) form = TestForm() form.helper = FormHelper() form.helper.html5_required = False html = render_crispy_form(form) def test_attrs(self): form = TestForm() form.helper = FormHelper() form.helper.attrs = {'id': 'TestIdForm', 'autocomplete': "off"} html = render_crispy_form(form) self.assertTrue('autocomplete="off"' in html) self.assertTrue('id="TestIdForm"' in html) def test_template_context(self): helper = FormHelper() helper.attrs = { 'id': 'test-form', 'class': 'test-forms', 'action': 'submit/test/form', 'autocomplete': 'off', } node = CrispyFormNode('form', 'helper') context = node.get_response_dict(helper, {}, False) self.assertEqual(context['form_id'], "test-form") self.assertEqual(context['form_attrs']['id'], "test-form") self.assertTrue("test-forms" in context['form_class']) self.assertTrue("test-forms" in context['form_attrs']['class']) self.assertEqual(context['form_action'], "submit/test/form") self.assertEqual(context['form_attrs']['action'], "submit/test/form") self.assertEqual(context['form_attrs']['autocomplete'], "off") def test_template_context_using_form_attrs(self): helper = FormHelper() helper.form_id = 'test-form' helper.form_class = 'test-forms' helper.form_action = 'submit/test/form' node = CrispyFormNode('form', 'helper') context = node.get_response_dict(helper, {}, False) self.assertEqual(context['form_id'], "test-form") self.assertEqual(context['form_attrs']['id'], "test-form") self.assertTrue("test-forms" in context['form_class']) self.assertTrue("test-forms" in context['form_attrs']['class']) self.assertEqual(context['form_action'], "submit/test/form") self.assertEqual(context['form_attrs']['action'], "submit/test/form") def test_template_helper_access(self): helper = FormHelper() helper.form_id = 'test-form' self.assertEqual(helper['form_id'], 'test-form') def test_without_helper(self): template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy form %} """) c = Context({'form': TestForm()}) html = template.render(c) # Lets make sure everything loads right self.assertTrue('= 1.4 is not wrapping exceptions in TEMPLATE_DEBUG mode if settings.TEMPLATE_DEBUG and django.get_version() < '1.4': self.assertRaises(TemplateSyntaxError, lambda:template.render(c)) else: self.assertRaises(TypeError, lambda:template.render(c)) del settings.CRISPY_FAIL_SILENTLY def test_formset_with_helper_without_layout(self): template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy testFormSet formset_helper %} """) form_helper = FormHelper() form_helper.form_id = 'thisFormsetRocks' form_helper.form_class = 'formsets-that-rock' form_helper.form_method = 'POST' form_helper.form_action = 'simpleAction' TestFormSet = formset_factory(TestForm, extra = 3) testFormSet = TestFormSet() c = Context({'testFormSet': testFormSet, 'formset_helper': form_helper, 'csrf_token': _get_new_csrf_key()}) html = template.render(c) self.assertEqual(html.count('Special custom form" in html) def test_helper_custom_field_template(self): form = TestForm() form.helper = FormHelper() form.helper.layout = Layout( 'password1', 'password2', ) form.helper.field_template = 'custom_field_template.html' html = render_crispy_form(form) self.assertEqual(html.count("

    Special custom field

    "), 2) class TestBootstrapFormHelper(CrispyTestCase): urls = 'crispy_forms.tests.urls' def test_form_show_errors(self): form = TestForm({ 'email': 'invalidemail', 'first_name': 'first_name_too_long', 'last_name': 'last_name_too_long', 'password1': 'yes', 'password2': 'yes', }) form.helper = FormHelper() form.helper.layout = Layout( AppendedText('email', 'whatever'), PrependedText('first_name', 'blabla'), PrependedAppendedText('last_name', 'foo', 'bar'), MultiField('legend', 'password1', 'password2') ) form.is_valid() form.helper.form_show_errors = True html = render_crispy_form(form) self.assertEqual(html.count('error'), 6) form.helper.form_show_errors = False html = render_crispy_form(form) self.assertEqual(html.count('error'), 0) def test_error_text_inline(self): form = TestForm({'email': 'invalidemail'}) form.helper = FormHelper() layout = Layout( AppendedText('first_name', 'wat'), PrependedText('email', '@'), PrependedAppendedText('last_name', '@', 'wat'), ) form.helper.layout = layout form.is_valid() html = render_crispy_form(form) help_class = 'help-inline' if self.current_template_pack == 'bootstrap3': help_class = 'help-block' matches = re.findall( '') error_position = html.find('

    ') self.assertTrue(help_position < error_position) # Viceversa form = TestForm({'email': 'invalidemail'}) form.helper = FormHelper() form.helper.error_text_inline = True form.helper.help_text_inline = False form.helper.layout = Layout('email') form.is_valid() html = render_crispy_form(form) # Check that error goes before help, otherwise CSS won't work error_position = html.find('') help_position = html.find('

    ') self.assertTrue(error_position < help_position) def test_form_show_labels(self): form = TestForm() form.helper = FormHelper() form.helper.layout = Layout( 'password1', FieldWithButtons( 'password2', StrictButton("Confirm") ), PrependedText( 'first_name', 'Mr.' ), AppendedText( 'last_name', '@' ), PrependedAppendedText( 'datetime_field', 'on', 'secs' ) ) form.helper.form_show_labels = False html = render_crispy_form(form) self.assertEqual(html.count("test link'), HTML(u""" {% if flag %}{{ message }}{% endif %} """), u'first_name', u'last_name', ) ) ) template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy form form_helper %} """) c = Context({ 'form': TestForm(), 'form_helper': form_helper, 'flag': True, 'message': "Hello!", }) html = template.render(c) self.assertTrue('id="fieldset_company_data"' in html) self.assertTrue('class="fieldsets' in html) self.assertTrue('title="fieldset_title"' in html) self.assertTrue('test-fieldset="123"' in html) self.assertTrue('id="row_passwords"' in html) self.assertEqual(html.count('' in html) self.assertTrue('input type="submit"' in html) self.assertTrue('button white' in html) self.assertTrue('data-id="test"' in html) self.assertTrue('data-name="test"' in html) self.assertTrue('name="save-the-world"' in html) self.assertTrue('value="Save"' in html) self.assertTrue('name="store"' in html) self.assertTrue('value="Store results"' in html) self.assertTrue('id="custom-div"' in html) self.assertTrue('class="customdivs"' in html) self.assertTrue('test-markup="123"' in html) def test_layout_composition(self): form_helper = FormHelper() form_helper.add_layout( Layout( Layout( MultiField("Some company data", 'is_company', 'email', css_id = "multifield_info", ), ), Column( 'first_name', # 'last_name', Missing a field on purpose css_id = "column_name", css_class = "columns", ), ButtonHolder( Submit('Save', 'Save', css_class='button white'), ), Div( 'password1', 'password2', css_id="custom-div", css_class="customdivs", ) ) ) template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy form form_helper %} """) c = Context({'form': TestForm(), 'form_helper': form_helper}) html = template.render(c) self.assertTrue('multiField' in html) self.assertTrue('formColumn' in html) self.assertTrue('id="multifield_info"' in html) self.assertTrue('id="column_name"' in html) self.assertTrue('class="formColumn columns"' in html) self.assertTrue('class="buttonHolder">' in html) self.assertTrue('input type="submit"' in html) self.assertTrue('name="Save"' in html) self.assertTrue('id="custom-div"' in html) self.assertTrue('class="customdivs"' in html) self.assertFalse('last_name' in html) def test_change_layout_dynamically_delete_field(self): template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy form form_helper %} """) form = TestForm() form_helper = FormHelper() form_helper.add_layout( Layout( Fieldset( u'Company Data', 'is_company', 'email', 'password1', 'password2', css_id = "multifield_info", ), Column( 'first_name', 'last_name', css_id = "column_name", ) ) ) # We remove email field on the go # Layout needs to be adapted for the new form fields del form.fields['email'] del form_helper.layout.fields[0].fields[1] c = Context({'form': form, 'form_helper': form_helper}) html = template.render(c) self.assertFalse('email' in html) def test_formset_layout(self): TestFormSet = formset_factory(TestForm, extra=3) formset = TestFormSet() helper = FormHelper() helper.form_id = 'thisFormsetRocks' helper.form_class = 'formsets-that-rock' helper.form_method = 'POST' helper.form_action = 'simpleAction' helper.layout = Layout( Fieldset("Item {{ forloop.counter }}", 'is_company', 'email', ), HTML("{% if forloop.first %}Note for first form only{% endif %}"), Row('password1', 'password2'), Fieldset("", 'first_name', 'last_name' ) ) html = render_crispy_form( form=formset, helper=helper, context={'csrf_token': _get_new_csrf_key()} ) # Check formset fields django_version = django.get_version() if django_version < '1.5': self.assertEqual(html.count( 'type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS"' ), 1) self.assertEqual(html.count( 'type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS"' ), 1) if (django_version >= '1.4' and django_version < '1.4.4') or django_version < '1.3.6': self.assertEqual(html.count( 'type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS"' ), 1) else: self.assertEqual(html.count( 'type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS"' ), 1) else: self.assertEqual(html.count( 'id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="3"' ), 1) self.assertEqual(html.count( 'id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0"' ), 1) self.assertEqual(html.count( 'id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000"' ), 1) self.assertEqual(html.count("hidden"), 4) # Check form structure self.assertEqual(html.count('= '1.4' and django_version < '1.4.4') or django_version < '1.3.6': self.assertEqual(html.count( 'type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS"' ), 1) else: self.assertEqual(html.count( 'type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS"' ), 1) else: self.assertEqual(html.count( 'id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="3"' ), 1) self.assertEqual(html.count( 'id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0"' ), 1) self.assertEqual(html.count( 'id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000"' ), 1) self.assertEqual(html.count('name="form-0-email"'), 1) self.assertEqual(html.count('name="form-1-email"'), 1) self.assertEqual(html.count('name="form-2-email"'), 1) self.assertEqual(html.count('name="form-3-email"'), 0) self.assertEqual(html.count('password'), 0) def test_i18n(self): template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {% crispy form form.helper %} """) form = TestForm() form_helper = FormHelper() form_helper.layout = Layout( HTML(_("i18n text")), Fieldset( _("i18n legend"), 'first_name', 'last_name', ) ) form.helper = form_helper html = template.render(Context({'form': form})) self.assertEqual(html.count('i18n legend'), 1) @override_settings(USE_L10N=True, USE_THOUSAND_SEPARATOR=True) def test_l10n(self): form = TestForm5(data={'pk': 1000}) html = render_crispy_form(form) # Make sure values are unlocalized self.assertTrue('value="1,000"' not in html) # Make sure label values are NOT localized self.assertTrue(html.count('1000'), 2) def test_default_layout(self): test_form = TestForm2() self.assertEqual(test_form.helper.layout.fields, [ 'is_company', 'email', 'password1', 'password2', 'first_name', 'last_name', 'datetime_field', ]) def test_default_layout_two(self): test_form = TestForm3() self.assertEqual(test_form.helper.layout.fields, ['email']) def test_modelform_layout_without_meta(self): test_form = TestForm4() test_form.helper = FormHelper() test_form.helper.layout = Layout('email') html = render_crispy_form(test_form) self.assertTrue('email' in html) self.assertFalse('password' in html) class TestBootstrapFormLayout(CrispyTestCase): urls = 'crispy_forms.tests.urls' def test_keepcontext_context_manager(self): # Test case for issue #180 # Apparently it only manifest when using render_to_response this exact way form = CheckboxesTestForm() form.helper = FormHelper() # We use here InlineCheckboxes as it updates context in an unsafe way form.helper.layout = Layout( 'checkboxes', InlineCheckboxes('alphacheckboxes'), 'numeric_multiple_checkboxes' ) request_factory = RequestFactory() request = request_factory.get('/') context = RequestContext(request, {'form': form}) response = render_to_response('crispy_render_template.html', context) if self.current_template_pack == 'bootstrap': self.assertEqual(response.content.count(b'checkbox inline'), 3) elif self.current_template_pack == 'bootstrap3': self.assertEqual(response.content.count(b'checkbox-inline'), 3) class TestBootstrap3FormLayout(CrispyTestCase): urls = 'crispy_forms.tests.urls' def test_form_inline(self): form = TestForm() form.helper = FormHelper() form.helper.form_class = 'form-inline' form.helper.field_template = 'bootstrap3/layout/inline_field.html' form.helper.layout = Layout( 'email', 'password1', 'last_name', ) html = render_crispy_form(form) self.assertEqual(html.count('class="form-inline"'), 1) self.assertEqual(html.count('class="form-group"'), 3) self.assertEqual(html.count('

    '), 2) self.assertEqual(html.count('
    '), 2) else: self.assertEqual(html.count('
    '), 2) self.assertEqual(html.count('
    One' ), 1 ) self.assertEqual(html.count('class="tab-pane first-tab-class active"'), 1) self.assertEqual(html.count('
  • everything is fine test_form = TestForm() html = render_crispy_form(test_form) # second render of form => first tab should be active, # but not duplicate class test_form = TestForm() html = render_crispy_form(test_form) self.assertEqual(html.count('class="tab-pane active active"'), 0) # render a new form, now with errors test_form = TestForm(data={'val1': 'foo'}) html = render_crispy_form(test_form) # tab 1 should not be active self.assertEqual(html.count('
    Passwords dont match
  • " in html) self.assertFalse("

    " in html) def test_crispy_filter_with_form(self): template = loader.get_template_from_string(u""" {% load crispy_forms_tags %} {{ form|crispy }} """) c = Context({'form': TestForm()}) html = template.render(c) self.assertTrue("" not in html) self.assertTrue("id_is_company" in html) self.assertEqual(html.count('= '1.5': from django.conf.urls import patterns, url else: from django.conf.urls.defaults import patterns, url urlpatterns = patterns('', url(r'^simple/action/$', 'simpleAction', name = 'simpleAction'), ) django-crispy-forms-1.4.0/crispy_forms/tests/utils.py000066400000000000000000000046761221066745500230310ustar00rootroot00000000000000__all__ = ('override_settings',) try: from django.test.utils import override_settings except ImportError: # we are in Django 1.3 from django.conf import settings, UserSettingsHolder from django.utils.functional import wraps class override_settings(object): """ Acts as either a decorator, or a context manager. If it's a decorator it takes a function and returns a wrapped function. If it's a contextmanager it's used with the ``with`` statement. In either event entering/exiting are called before and after, respectively, the function/block is executed. This class was backported from Django 1.5 As django.test.signals.setting_changed is not supported in 1.3, it's not sent on changing settings. """ def __init__(self, **kwargs): self.options = kwargs self.wrapped = settings._wrapped def __enter__(self): self.enable() def __exit__(self, exc_type, exc_value, traceback): self.disable() def __call__(self, test_func): from django.test import TransactionTestCase if isinstance(test_func, type): if not issubclass(test_func, TransactionTestCase): raise Exception( "Only subclasses of Django SimpleTestCase " "can be decorated with override_settings") original_pre_setup = test_func._pre_setup original_post_teardown = test_func._post_teardown def _pre_setup(innerself): self.enable() original_pre_setup(innerself) def _post_teardown(innerself): original_post_teardown(innerself) self.disable() test_func._pre_setup = _pre_setup test_func._post_teardown = _post_teardown return test_func else: @wraps(test_func) def inner(*args, **kwargs): with self: return test_func(*args, **kwargs) return inner def enable(self): override = UserSettingsHolder(settings._wrapped) for key, new_value in self.options.items(): setattr(override, key, new_value) settings._wrapped = override def disable(self): settings._wrapped = self.wrapped django-crispy-forms-1.4.0/crispy_forms/utils.py000066400000000000000000000160721221066745500216600ustar00rootroot00000000000000from __future__ import with_statement import inspect import logging import sys from django.conf import settings from django.forms.forms import BoundField from django.template import Context from django.template.loader import get_template from django.utils.html import conditional_escape from django.utils.functional import memoize from .base import KeepContext from .compatibility import text_type, PY2 # Global field template, default template used for rendering a field. TEMPLATE_PACK = getattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap') # By memoizeing we avoid loading the template every time render_field # is called without a template def default_field_template(template_pack=TEMPLATE_PACK): return get_template("%s/field.html" % template_pack) default_field_template = memoize(default_field_template, {}, 1) def render_field(field, form, form_style, context, template=None, labelclass=None, layout_object=None, attrs=None, template_pack=TEMPLATE_PACK): """ Renders a django-crispy-forms field :param field: Can be a string or a Layout object like `Row`. If it's a layout object, we call its render method, otherwise we instantiate a BoundField and render it using default template 'CRISPY_TEMPLATE_PACK/field.html' The field is added to a list that the form holds called `rendered_fields` to avoid double rendering fields. :param form: The form/formset to which that field belongs to. :param form_style: A way to pass style name to the CSS framework used. :template: Template used for rendering the field. :layout_object: If passed, it points to the Layout object that is being rendered. We use it to store its bound fields in a list called `layout_object.bound_fields` :attrs: Attributes for the field's widget """ with KeepContext(context): FAIL_SILENTLY = getattr(settings, 'CRISPY_FAIL_SILENTLY', True) if hasattr(field, 'render'): if 'template_pack' in inspect.getargspec(field.render)[0]: return field.render(form, form_style, context, template_pack=template_pack) else: return field.render(form, form_style, context) else: # In Python 2 form field names cannot contain unicode characters without ASCII mapping if PY2: # This allows fields to be unicode strings, always they don't use non ASCII try: if isinstance(field, text_type): field = field.encode('ascii').decode() # If `field` is not unicode then we turn it into a unicode string, otherwise doing # str(field) would give no error and the field would not be resolved, causing confusion else: field = text_type(field) except (UnicodeEncodeError, UnicodeDecodeError): raise Exception("Field '%s' is using forbidden unicode characters" % field) try: # Injecting HTML attributes into field's widget, Django handles rendering these field_instance = form.fields[field] if attrs is not None: widgets = getattr(field_instance.widget, 'widgets', [field_instance.widget]) # We use attrs as a dictionary later, so here we make a copy list_attrs = attrs if isinstance(attrs, dict): list_attrs = [attrs] * len(widgets) for index, (widget, attr) in enumerate(zip(widgets, list_attrs)): if hasattr(field_instance.widget, 'widgets'): if 'type' in attr and attr['type'] == "hidden": field_instance.widget.widgets[index].is_hidden = True field_instance.widget.widgets[index] = field_instance.hidden_widget() field_instance.widget.widgets[index].attrs.update(attr) else: if 'type' in attr and attr['type'] == "hidden": field_instance.widget.is_hidden = True field_instance.widget = field_instance.hidden_widget() field_instance.widget.attrs.update(attr) except KeyError: if not FAIL_SILENTLY: raise Exception("Could not resolve form field '%s'." % field) else: field_instance = None logging.warning("Could not resolve form field '%s'." % field, exc_info=sys.exc_info()) if hasattr(form, 'rendered_fields'): if not field in form.rendered_fields: form.rendered_fields.add(field) else: if not FAIL_SILENTLY: raise Exception("A field should only be rendered once: %s" % field) else: logging.warning("A field should only be rendered once: %s" % field, exc_info=sys.exc_info()) if field_instance is None: html = '' else: bound_field = BoundField(form, field_instance, field) if template is None: if form.crispy_field_template is None: template = default_field_template(template_pack) else: # FormHelper.field_template set template = get_template(form.crispy_field_template) else: template = get_template(template) # We save the Layout object's bound fields in the layout object's `bound_fields` list if layout_object is not None: if hasattr(layout_object, 'bound_fields') and isinstance(layout_object.bound_fields, list): layout_object.bound_fields.append(bound_field) else: layout_object.bound_fields = [bound_field] context.update({ 'field': bound_field, 'labelclass': labelclass, 'flat_attrs': flatatt(attrs if isinstance(attrs, dict) else {}), }) html = template.render(context) return html def flatatt(attrs): """ Taken from django.core.utils Convert a dictionary of attributes to a single string. The returned string will contain a leading space followed by key="value", XML-style pairs. It is assumed that the keys do not need to be XML-escaped. If the passed dictionary is empty, then return an empty string. """ return u''.join([u' %s="%s"' % (k.replace('_', '-'), conditional_escape(v)) for k, v in attrs.items()]) def render_crispy_form(form, helper=None, context=None): """ Renders a form and returns its HTML output. This function wraps the template logic in a function easy to use in a Django view. """ from crispy_forms.templatetags.crispy_forms_tags import CrispyFormNode if helper is not None: node = CrispyFormNode('form', 'helper') else: node = CrispyFormNode('form', None) node_context = Context(context) node_context.update({ 'form': form, 'helper': helper }) return node.render(node_context) django-crispy-forms-1.4.0/docs/000077500000000000000000000000001221066745500163515ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/.DS_Store000066400000000000000000000140041221066745500200330ustar00rootroot00000000000000Bud1lddsclbool_builddsclbool  @ @ @ @ EDSDB ` @ @ @django-crispy-forms-1.4.0/docs/Makefile000077500000000000000000000057031221066745500200210ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf _build/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @echo "Build finished. The HTML pages are in _build/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml @echo @echo "Build finished. The HTML pages are in _build/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in _build/qthelp, like this:" @echo "# qcollectiongenerator _build/qthelp/django-uni-form.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile _build/qthelp/django-uni-form.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in _build/doctest/output.txt." django-crispy-forms-1.4.0/docs/__init__.py000066400000000000000000000000001221066745500204500ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_templates/000077500000000000000000000000001221066745500205065ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_templates/sidebarintro.html000066400000000000000000000022311221066745500240570ustar00rootroot00000000000000

    crispy-forms

    django-crispy-forms is a Django application that lets you easily build, customize and reuse forms using your favorite CSS framework, without writing template code and without having to take care of annoying details. You are currently looking at the documentation of the development release.

    Support

    If you love django-crispy-forms, consider making a small donation on Flattr:

    django-crispy-forms-1.4.0/docs/_themes/000077500000000000000000000000001221066745500177755ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_themes/LICENSE000066400000000000000000000035071221066745500210070ustar00rootroot00000000000000Modifications: Copyright (c) 2010 Kenneth Reitz. Original Project: Copyright (c) 2010 by Armin Ronacher. Some rights reserved. Redistribution and use in source and binary forms of the theme, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. We kindly ask you to only use these themes in an unmodified manner just for Flask and Flask-related products, not for unrelated projects. If you like the visual style and want to use it for your own projects, please consider making some larger changes to the themes (such as changing font faces, sizes, colors or margins). THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. django-crispy-forms-1.4.0/docs/_themes/flask_theme_support.py000066400000000000000000000114131221066745500244250ustar00rootroot00000000000000# flasky extensions. flasky pygments style based on tango style from pygments.style import Style from pygments.token import Keyword, Name, Comment, String, Error, \ Number, Operator, Generic, Whitespace, Punctuation, Other, Literal class FlaskyStyle(Style): background_color = "#f8f8f8" default_style = "" styles = { # No corresponding class for the following: #Text: "", # class: '' Whitespace: "underline #f8f8f8", # class: 'w' Error: "#a40000 border:#ef2929", # class: 'err' Other: "#000000", # class 'x' Comment: "italic #8f5902", # class: 'c' Comment.Preproc: "noitalic", # class: 'cp' Keyword: "bold #004461", # class: 'k' Keyword.Constant: "bold #004461", # class: 'kc' Keyword.Declaration: "bold #004461", # class: 'kd' Keyword.Namespace: "bold #004461", # class: 'kn' Keyword.Pseudo: "bold #004461", # class: 'kp' Keyword.Reserved: "bold #004461", # class: 'kr' Keyword.Type: "bold #004461", # class: 'kt' Operator: "#582800", # class: 'o' Operator.Word: "bold #004461", # class: 'ow' - like keywords Punctuation: "bold #000000", # class: 'p' # because special names such as Name.Class, Name.Function, etc. # are not recognized as such later in the parsing, we choose them # to look the same as ordinary variables. Name: "#000000", # class: 'n' Name.Attribute: "#c4a000", # class: 'na' - to be revised Name.Builtin: "#004461", # class: 'nb' Name.Builtin.Pseudo: "#3465a4", # class: 'bp' Name.Class: "#000000", # class: 'nc' - to be revised Name.Constant: "#000000", # class: 'no' - to be revised Name.Decorator: "#888", # class: 'nd' - to be revised Name.Entity: "#ce5c00", # class: 'ni' Name.Exception: "bold #cc0000", # class: 'ne' Name.Function: "#000000", # class: 'nf' Name.Property: "#000000", # class: 'py' Name.Label: "#f57900", # class: 'nl' Name.Namespace: "#000000", # class: 'nn' - to be revised Name.Other: "#000000", # class: 'nx' Name.Tag: "bold #004461", # class: 'nt' - like a keyword Name.Variable: "#000000", # class: 'nv' - to be revised Name.Variable.Class: "#000000", # class: 'vc' - to be revised Name.Variable.Global: "#000000", # class: 'vg' - to be revised Name.Variable.Instance: "#000000", # class: 'vi' - to be revised Number: "#990000", # class: 'm' Literal: "#000000", # class: 'l' Literal.Date: "#000000", # class: 'ld' String: "#4e9a06", # class: 's' String.Backtick: "#4e9a06", # class: 'sb' String.Char: "#4e9a06", # class: 'sc' String.Doc: "italic #8f5902", # class: 'sd' - like a comment String.Double: "#4e9a06", # class: 's2' String.Escape: "#4e9a06", # class: 'se' String.Heredoc: "#4e9a06", # class: 'sh' String.Interpol: "#4e9a06", # class: 'si' String.Other: "#4e9a06", # class: 'sx' String.Regex: "#4e9a06", # class: 'sr' String.Single: "#4e9a06", # class: 's1' String.Symbol: "#4e9a06", # class: 'ss' Generic: "#000000", # class: 'g' Generic.Deleted: "#a40000", # class: 'gd' Generic.Emph: "italic #000000", # class: 'ge' Generic.Error: "#ef2929", # class: 'gr' Generic.Heading: "bold #000080", # class: 'gh' Generic.Inserted: "#00A000", # class: 'gi' Generic.Output: "#888", # class: 'go' Generic.Prompt: "#745334", # class: 'gp' Generic.Strong: "bold #000000", # class: 'gs' Generic.Subheading: "bold #800080", # class: 'gu' Generic.Traceback: "bold #a40000", # class: 'gt' } django-crispy-forms-1.4.0/docs/_themes/kr/000077500000000000000000000000001221066745500204115ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_themes/kr/layout.html000066400000000000000000000017271221066745500226230ustar00rootroot00000000000000{%- extends "basic/layout.html" %} {%- block extrahead %} {{ super() }} {% if theme_touch_icon %} {% endif %} {% endblock %} {%- block relbar2 %}{% endblock %} {%- block footer %} {%- endblock %} django-crispy-forms-1.4.0/docs/_themes/kr/relations.html000066400000000000000000000011161221066745500232760ustar00rootroot00000000000000

    Related Topics

    django-crispy-forms-1.4.0/docs/_themes/kr/static/000077500000000000000000000000001221066745500217005ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_themes/kr/static/flasky.css_t000066400000000000000000000157101221066745500242320ustar00rootroot00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * :copyright: Copyright 2010 by Armin Ronacher. Modifications by Kenneth Reitz. * :license: Flask Design License, see LICENSE for details. */ {% set page_width = '940px' %} {% set sidebar_width = '220px' %} @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro'; font-size: 17px; background-color: white; color: #000; margin: 0; padding: 0; } div.document { width: {{ page_width }}; margin: 30px auto 0 auto; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 {{ sidebar_width }}; } div.sphinxsidebar { width: {{ sidebar_width }}; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 0 30px; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { width: {{ page_width }}; margin: 20px auto 30px auto; font-size: 14px; color: #888; text-align: right; } div.footer a { color: #888; } div.related { display: none; } div.sphinxsidebar a { color: #444; text-decoration: none; border-bottom: 1px dotted #999; } div.sphinxsidebar a:hover { border-bottom: 1px solid #999; } div.sphinxsidebar { font-size: 14px; line-height: 1.5; } div.sphinxsidebarwrapper { padding: 0px 10px; } div.sphinxsidebarwrapper p.logo { padding: 0 0 20px 0; margin: 0; text-align: center; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: 'Garamond', 'Georgia', serif; color: #555; font-size: 24px; font-weight: normal; margin: 0 0 5px 0; padding: 0; } div.sphinxsidebar h4 { font-size: 20px; } div.sphinxsidebar h3 a { color: #444; } div.sphinxsidebar p.logo a, div.sphinxsidebar h3 a, div.sphinxsidebar p.logo a:hover, div.sphinxsidebar h3 a:hover { border: none; } div.sphinxsidebar p { color: #555; margin: 10px 0; } div.sphinxsidebar ul { margin: 10px 0; padding: 0; color: #000; } div.sphinxsidebar input[type="text"] { width: 160px!important; } div.sphinxsidebar input { border: 1px solid #ccc; font-family: 'Georgia', serif; font-size: 1em; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: #ddd; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition tt.xref, div.admonition a tt { border-bottom: 1px solid #fafafa; } dd div.admonition { margin-left: -60px; padding-left: 60px; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight { background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.9em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; background: #fdfdfd; font-size: 0.9em; } table.footnote + table.footnote { margin-top: -15px; border-top: none; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td.label { width: 0px; padding: 0.3em 0 0.3em 0.5em; } table.footnote td { padding: 0.3em 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } blockquote { margin: 0 0 0 30px; padding: 0; } ul, ol { margin: 10px 0 10px 30px; padding: 0; } pre { background: #eee; padding: 7px 30px; margin: 15px -30px; line-height: 1.3em; } dl pre, blockquote pre, li pre { margin-left: -60px; padding-left: 60px; } dl dl pre { margin-left: -90px; padding-left: 90px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; border-bottom: 1px solid white; } a.reference { text-decoration: none; border-bottom: 1px dotted #004B6B; } a.reference:hover { border-bottom: 1px solid #6D4100; } a.footnote-reference { text-decoration: none; font-size: 0.7em; vertical-align: top; border-bottom: 1px dotted #004B6B; } a.footnote-reference:hover { border-bottom: 1px solid #6D4100; } a:hover tt { background: #EEE; } /* scrollbars */ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment { display: block; height: 10px; } ::-webkit-scrollbar-button:vertical:increment { background-color: #fff; } ::-webkit-scrollbar-track-piece { background-color: #eee; -webkit-border-radius: 3px; } ::-webkit-scrollbar-thumb:vertical { height: 50px; background-color: #ccc; -webkit-border-radius: 3px; } ::-webkit-scrollbar-thumb:horizontal { width: 50px; background-color: #ccc; -webkit-border-radius: 3px; } /* misc. */ .revsys-inline { display: none!important; } a.toc-backref { color: #3E4349; text-decoration: none; } django-crispy-forms-1.4.0/docs/_themes/kr/static/small_flask.css000066400000000000000000000017201221066745500247020ustar00rootroot00000000000000/* * small_flask.css_t * ~~~~~~~~~~~~~~~~~ * * :copyright: Copyright 2010 by Armin Ronacher. * :license: Flask Design License, see LICENSE for details. */ body { margin: 0; padding: 20px 30px; } div.documentwrapper { float: none; background: white; } div.sphinxsidebar { display: block; float: none; width: 102.5%; margin: 50px -30px -20px -30px; padding: 10px 20px; background: #333; color: white; } div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, div.sphinxsidebar h3 a { color: white; } div.sphinxsidebar a { color: #aaa; } div.sphinxsidebar p.logo { display: none; } div.document { width: 100%; margin: 0; } div.related { display: block; margin: 0; padding: 10px 0 20px 0; } div.related ul, div.related ul li { margin: 0; padding: 0; } div.footer { display: none; } div.bodywrapper { margin: 0; } div.body { min-height: 0; padding: 0; } django-crispy-forms-1.4.0/docs/_themes/kr/theme.conf000066400000000000000000000001721221066745500223620ustar00rootroot00000000000000[theme] inherit = basic stylesheet = flasky.css pygments_style = flask_theme_support.FlaskyStyle [options] touch_icon = django-crispy-forms-1.4.0/docs/_themes/kr_small/000077500000000000000000000000001221066745500216015ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_themes/kr_small/layout.html000066400000000000000000000012531221066745500240050ustar00rootroot00000000000000{% extends "basic/layout.html" %} {% block header %} {{ super() }} {% if pagename == 'index' %}
    {% endif %} {% endblock %} {% block footer %} {% if pagename == 'index' %}
    {% endif %} {% endblock %} {# do not display relbars #} {% block relbar1 %}{% endblock %} {% block relbar2 %} {% if theme_github_fork %} Fork me on GitHub {% endif %} {% endblock %} {% block sidebar1 %}{% endblock %} {% block sidebar2 %}{% endblock %} django-crispy-forms-1.4.0/docs/_themes/kr_small/static/000077500000000000000000000000001221066745500230705ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/_themes/kr_small/static/flasky.css_t000066400000000000000000000110011221066745500254070ustar00rootroot00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * Sphinx stylesheet -- flasky theme based on nature theme. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Georgia', serif; font-size: 17px; color: #000; background: white; margin: 0; padding: 0; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 40px auto 0 auto; width: 700px; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { text-align: right; color: #888; padding: 10px; font-size: 14px; width: 650px; margin: 0 auto 40px auto; } div.footer a { color: #888; text-decoration: underline; } div.related { line-height: 32px; color: #888; } div.related ul { padding: 0 0 0 10px; } div.related a { color: #444; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body { padding-bottom: 40px; /* saved for footer */ } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } {% if theme_index_logo %} div.indexwrapper h1 { text-indent: -999999px; background: url({{ theme_index_logo }}) no-repeat center center; height: {{ theme_index_logo_height }}; } {% endif %} div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: white; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight{ background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.85em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td { padding: 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } pre { padding: 0; margin: 15px -30px; padding: 8px; line-height: 1.3em; padding: 7px 30px; background: #eee; border-radius: 2px; -moz-border-radius: 2px; -webkit-border-radius: 2px; } dl pre { margin-left: -60px; padding-left: 60px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; } a:hover tt { background: #EEE; } django-crispy-forms-1.4.0/docs/_themes/kr_small/theme.conf000066400000000000000000000002701221066745500235510ustar00rootroot00000000000000[theme] inherit = basic stylesheet = flasky.css nosidebar = true pygments_style = flask_theme_support.FlaskyStyle [options] index_logo = '' index_logo_height = 120px github_fork = '' django-crispy-forms-1.4.0/docs/api_helpers.rst000066400000000000000000000002161221066745500213750ustar00rootroot00000000000000.. _`helpers api`: =================================== API helpers =================================== .. automodule:: helper :members: django-crispy-forms-1.4.0/docs/api_layout.rst000066400000000000000000000002141221066745500212460ustar00rootroot00000000000000.. _`layout api`: =================================== API Layout =================================== .. automodule:: layout :members: django-crispy-forms-1.4.0/docs/api_templatetags.rst000066400000000000000000000005251221066745500224300ustar00rootroot00000000000000========================================== API templatetags ========================================== .. automodule:: templatetags.crispy_forms_tags :members: :undoc-members: .. automodule:: templatetags.crispy_forms_filters :members: :undoc-members: .. automodule:: templatetags.crispy_forms_field :members: :undoc-members: django-crispy-forms-1.4.0/docs/concepts.rst000066400000000000000000000042301221066745500207200ustar00rootroot00000000000000======== Concepts ======== Form Helpers ------------- The biggest advantage of this library are :ref:`form helpers` and layouts. The advantage of these tools is that they let you build forms with most of the coding done in Python, rather than HTML. We **strongly** suggest you study and learn the examples in the :ref:`form helpers` documentation. Don't Repeat Yourself --------------------- It has been written that if you do anything twice in code, you should wrap it up in a function or method. This project was born out of the desire to not have to rewrite similar forms multiple times over the same project. Just like we use the Django ORM to avoid writing simple queries again and again, it is advantageous to our sanity and code quality to not have to write `
    ` 30 times across a project. The problem with building a form this way multiple times is that it is ripe for error. What about hidden fields? What if you forget the `{% csrf_token %}` token? What if you don't set the form method correctly? Think of django-uni-form like an ORM, it handles the small details so you can focus on the big picture of your project - the business logic that drives your site and is probably a lot more fun to deal with than the tiny particularities of forms. Section 508 ----------- Some years ago the United States congress defined `Section 508`_ as a means to provide enforcement for technology provided or purchased for the government that met a set of specifications so that those with disabilities could use said technologies. Unfortunately, the specification does not normally apply to commercial products not used by the US Government and many US Government projects weasel out of the specification. However, following Section 508 (and the World Wide Web Consortium's (W3C) `Web Accessibility Initiative`_ (WAI) is the right thing to do. It doesn't hurt to familiarize yourself with these specifications. In the meantime, django-uni-form provides a means to easily render Section 508 compliant forms. How awesome is that? .. _`Section 508`: http://en.wikipedia.org/wiki/Section_508 .. _`Web Accessibility Initiative`: http://en.wikipedia.org/wiki/Web_Accessibility_Initiative django-crispy-forms-1.4.0/docs/conf.py000077500000000000000000000154231221066745500176600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # django-crispy-forms documentation build configuration file, created by # sphinx-quickstart on Mon Mar 8 22:42:02 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('..')) sys.path.insert(0, os.path.abspath('../crispy_forms')) sys.path.insert(0, os.path.abspath('../crispy_forms/templatetags')) sys.path.append(os.path.abspath('_themes')) import settings from django.core.management import setup_environ setup_environ(settings) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'django-crispy-forms' copyright = u'2009-2013, Miguel Araujo and Daniel Greenfeld' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. release = '1.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'kr' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['_themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], '**': ['sidebarintro.html', 'localtoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'django-crispy-formdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'django-crispy-forms.tex', u'django-crispy-forms Documentation', u'Miguel Araujo', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True django-crispy-forms-1.4.0/docs/contributing.rst000066400000000000000000000147501221066745500216210ustar00rootroot00000000000000============ Contributing ============ Setup ===== Fork on github -------------- Before you do anything else, login/signup on Github.com and fork django-crispy-forms from https://github.com/maraujop/django-crispy-forms. Clone your fork locally ----------------------- If you have git-scm installed, you now clone your git repo using the following command-line argument where is your account name on github:: git clone git@github.com//django-crispy-forms.git Setting up topic branches and generating pull requests ====================================================== While it's handy to provide useful code snippets in an issue, it is better for you as a developer to submit pull requests. By submitting pull request your contribution to django-crispy-forms will be recorded by Github. In git it is best to isolate each topic or feature into a "topic branch". While individual commits allow you control over how small individual changes are made to the code, branches are a great way to group a set of commits all related to one feature together, or to isolate different efforts when you might be working on multiple topics at the same time. While it takes some experience to get the right feel about how to break up commits, a topic branch **must** be limited in scope to a single ``issue`` as submitted to an issue tracker. Also since github pegs and syncs a pull request to a specific branch, it is the **ONLY** way that you can submit more than one fix at a time. If you submit a pull from your master branch, you can't make any more commits to your master without those getting added to the pull. To create a topic branch, its easiest to use the convenient ``-b`` argument to ``git checkout``:: git checkout -b fix-broken-thing Switched to a new branch 'fix-broken-thing' You should use a verbose enough name for your branch so it is clear what it is about. Now you can commit your changes and regularly merge in the upstream master as described below. When you are ready to generate a pull request, either for preliminary review, or for consideration of merging into the project you must first push your local topic branch back up to github:: git push origin fix-broken-thing Now when you go to your fork on github, you will see this branch listed under the "Source" tab where it says "Switch Branches". Go ahead and select your topic branch from this list, and then click the "Pull request" button. Here you can add a comment about your branch. If this in response to a submitted issue, it is good to put a link to that issue in this initial comment. The repo managers will be notified of your pull request and it will be reviewed (see below for best practices). Note that you can continue to add commits to your topic branch (and push them up to github) either if you see something that needs changing, or in response to a reviewer's comments. If a reviewer asks for changes, you do not need to close the pull and reissue it after making changes. Just make the changes locally, push them to github, then add a comment to the discussion section of the pull request. Pull upstream changes into your fork regularly ================================================== django-crispy-forms is worked on by a lot of people. It is therefore critical that you pull upstream changes from trunk into your fork on a regular basis. Nothing is worse than putting in days of hard work into a pull request only to have it rejected because it has diverged too far from trunk. To pull in upstream changes:: git remote add trunk git://github.com/maraujop/django-crispy-forms.git git fetch trunk Check the log to be sure that you actually want the changes, before merging:: git log ..django-crispy-forms/master Then merge the changes that you fetched:: git merge django-crispy-forms/master For more info, see http://help.github.com/fork-a-repo/ How to get your Pull Request accepted ===================================== We want your submission. But we also want to provide a stable experience for our users and the community. Follow these rules and you should succeed without a problem! Run the tests! -------------- Before you submit a pull request, please run the entire django-crispy-forms test suite via:: cd crispy_forms/tests ./runtests.py The first thing the core committers will do is run this command. Any pull request that fails this test suite will be **rejected**. It's always good to add tests! ------------------------------ We've learned the hard way that code without tests is undependable. If your pull request comes with tests, it's got a greater chance to be included. Otherwise the lead will ask you to code them or will help you doing so. We use the Django Test framework (based on unittest). Also, keep your tests as simple as possible. Complex tests end up requiring their own tests. We would rather see duplicated assertions across test methods then cunning utility methods that magically determine which assertions are needed at a particular stage. Remember: `Explicit is better than implicit`. Don't mix code changes with whitespace cleanup ---------------------------------------------- If you change two lines of code and correct 200 lines of whitespace issues in a file the diff on that pull request is functionally unreadable and will be **rejected**. Whitespace cleanups need to be in their own pull request. Keep your pull requests limited to a single issue -------------------------------------------------- django-crispy-forms pull requests should be as small/atomic as possible. Large, wide-sweeping changes in a pull request will be **rejected**, with comments to isolate the specific code in your pull request. Some examples: #. If you are fixing a bug in one helper class don't '*cleanup*' unrelated helpers. That cleanup belongs in another pull request. #. Changing permissions on a file should be in its own pull request with explicit reasons why. Keep your code simple! ---------------------- Memorize the Zen of Python:: >>> python -c 'import this' Please keep your code as clean and straightforward as possible. When we see more than one or two functions/methods starting with `_my_special_function` or things like `__builtins__.object = str` we start to get worried. Rather than try and figure out your brilliant work we'll just **reject** it and send along a request for simplification. Furthermore, the pixel shortage is over. We want to see: * `helper` instead of `hpr` * `django-crispy-forms` instead of `dcf` * `my_function_that_does_things` instead of `mftdt` django-crispy-forms-1.4.0/docs/crispy_tag_forms.rst000066400000000000000000000346371221066745500224720ustar00rootroot00000000000000.. _`crispy tag forms`: =========================== {% crispy %} tag with forms =========================== django-crispy-forms implements a class called ``FormHelper`` that defines the form rendering behavior. Helpers give you a way to control form attributes and its layout, doing this in a programatic way using Python. This way you write as little HTML as possible, and all your logic stays in the forms and views files. Fundamentals ~~~~~~~~~~~~ For the rest of this document we will use the following example form for showing how to use a helper. This form is in charge of gathering some user information:: class ExampleForm(forms.Form): like_website = forms.TypedChoiceField( label = "Do you like this website?", choices = ((1, "Yes"), (0, "No")), coerce = lambda x: bool(int(x)), widget = forms.RadioSelect, initial = '1', required = True, ) favorite_food = forms.CharField( label = "What is your favorite food?", max_length = 80, required = True, ) favorite_color = forms.CharField( label = "What is your favorite color?", max_length = 80, required = True, ) favorite_number = forms.IntegerField( label = "Favorite number", required = False, ) notes = forms.CharField( label = "Additional notes or feedback", required = False, ) Let's see how helpers works step by step, with some examples explained. First you will need to import ``FormHelper``:: from crispy_forms.helper import FormHelper Your helper can be a class level variable or an instance level variable, if you don't know what this means you might want to read the article "`Be careful how you use static variables in forms`_". As a rule of thumb, if you are not going to manipulate a `FormHelper` in your code, like in a view, you should be using a static helper, otherwise you should be using an instance level helper. If you still don't understand the subtle differences between both, use an instance level helper, because you won't end up suffering side effects. As in the next steps I will show you how to manipulate the form helper, so we will create an instance level helper. This is how you would do it:: from crispy_forms.helper import FormHelper class ExampleForm(forms.Form): [...] def __init__(self, *args, **kwargs): super(ExampleForm, self).__init__(*args, **kwargs) self.helper = FormHelper() As you can see you need to call the base class constructor using ``super`` and override the constructor. This helper doesn't set any form attributes, so it's useless. Let's see how to set up some basic `FormHelper` attributes:: from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit class ExampleForm(forms.Form): [...] def __init__(self, *args, **kwargs): super(ExampleForm, self).__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_id = 'id-exampleForm' self.helper.form_class = 'blueForms' self.helper.form_method = 'post' self.helper.form_action = 'submit_survey' self.helper.add_input(Submit('submit', 'Submit')) Note that we are importing a class called ``Submit`` that is a layout object. We will see what layout objects are in detail later on, for now on let's just say that this adds a submit button to our form, so people can send their survey. We've also done some helper magic. ``FormHelper`` has a list of attributes that can be set, that effect mainly form attributes. Our form will have as DOM id ``id-exampleForm``, it will have as DOM CSS class ``blueForms``, it will use http ``POST`` to send information and its action will be set to ``reverse(submit_survey)``. Let's see how to render the form in a template. Supposing we have the form in the template context as ``example_form``, we would render it doing:: {% load crispy_forms_tags %} {% crispy example_form example_form.helper %} Notice that the ``{% crispy %}`` tags expects two parameters: first the form variable and then the helper. In this case we use the ``FormHelper`` attached to the form, but you could also create a ``FormHelper`` instance and pass it as a context variable. Most of the time, you will want to use the helper attached. Note that if you name your ``FormHelper`` attribute ``helper`` you will only need to do:: {% crispy form %} This is exactly the html that you would get::
    What you'll get is the form rendered as HTML with awesome bits. Specifically... * Opening and closing form tags, with id, class, action and method set as in the helper::
    [...]
    * Django's CSRF controls::
    * Submit button::
    .. _`Be careful how you use static variables in forms`: http://tothinkornottothink.com/post/7157151391/be-careful-how-you-use-static-variables-in-forms Manipulating a helper in a view ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Let's see how we could change any helper property in a view:: @login_required() def inbox(request, template_name): example_form = ExampleForm() redirect_url = request.GET.get('next') # Form handling logic [...] if redirect_url is not None: example_form.helper.form_action = reverse('submit_survey') + '?next=' + redirectUrl return render_to_response(template_name, {'example_form': example_form}, context_instance=RequestContext(request)) We are changing ``form_action`` helper property in case the view was called with a ``next`` GET parameter. Rendering several forms with helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Often we get asked: "How do you render two or more forms, with their respective helpers, using ``{% crispy %}`` tag, without having ``
    `` tags rendered twice?" Easy, you need to set ``form_tag`` helper property to ``False`` in every helper:: self.helper.form_tag = False Then you will have to write a little of html code surrounding the forms:: {% crispy first_form %} {% crispy second_form %}
    You can read a list of :ref:`helper attributes` and what they are for. Change '*' required fields ~~~~~~~~~~~~~~~~~~~~~~~~~~ If you don't like the use of ``*`` (asterisk) to denote required fields you have two options: * Asterisks have an ``asteriskField`` class set. So you can hide it using CSS rule:: .asteriskField { display: none; } * Override ``field.html`` template with a custom one. Make crispy-forms fail loud ~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default when crispy-forms encounters errors, it fails silently, logs them and continues working if possible. A settings variable called ``CRISPY_FAIL_SILENTLY`` has been added so that you can control this behavior. If you want to raise exceptions instead of logging, telling you what’s going on when you are developing in debug mode, you can set it to:: CRISPY_FAIL_SILENTLY = not DEBUG Change crispy-forms default classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django fields generate default classes, crispy-forms handles these and adds other classes for compatibility with CSS frameworks. For example a ``CharField`` generates an `` {% crispy formset helper %}
    Finally, model formsets and inline formsets are rendered exactly the same as formsets, the only difference is how you build them in your Django code. .. _`Django official formset docs`: https://docs.djangoproject.com/en/dev/topics/forms/formsets/ Extra context ~~~~~~~~~~~~~ Rendering any kind of formset with crispy injects some extra context in the layout rendering so that you can do things like:: HTML("{% if forloop.first %}Message displayed only in the first form of a formset forms list{% endif %}", Fieldset("Item {{ forloop.counter }}", 'field-1', [...]) Basically you can access a ``forloop`` Django node, as if you were rendering your formsets forms using a for loop. Custom templates and table inline formsets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Default formset template will render your formset's form using divs, but many times people prefer tables for formsets. Don't worry, crispy-forms's got you covered. ``FormHelper`` has an attribute named ``template`` that can be used to specify a custom template for rendering a form or formset, in this case a formset. Obviously when we specify a ``template`` attribute, we are making that helper only usuable with forms or formsets. The name of the template to use is **table_inline_formset.html** and you use it doing:: helper.template = 'bootstrap/table_inline_formset.html' The best part is that if this template doesn't do exactly what you want, you can copy it into your templates folder, customize it and then link your helper to your alternative version. If you think what you are missing would be valuable to others, then please submit a pull request at github. .. warning :: This template doesn't currently take into account any layout you have specified and only works with bootstrap template pack. Formset forms with different layouts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default crispy-forms formset rendering shares the same layout among all formset's forms. This is the case 99% of the times. But maybe you want to render your formset's forms using different layouts that you cannot achieve using the extra context injected, for that you will have to create and use a custom template. Most likely you will want to do:: {{ formset.management_form|crispy }} {% for form in formset %} {% crispy form %} {% endfor %} Where every ``form`` has a ``helper`` attribute from which crispy will grab the layout. In your view you will need to change the layout or use a different help for every formset's form. Make sure that you have ``form_tag`` attribute set to ``False``, otherwise you will get 3 individual forms rendered. django-crispy-forms-1.4.0/docs/dynamic_layouts.rst000066400000000000000000000235671221066745500223240ustar00rootroot00000000000000.. _`dynamic layouts`: ========================== Updating layouts on the go ========================== Layouts can be changed, adapted and generated programmatically. The next sections will explain how to select parts of a layout and update them. We will use this API from the ``FormHelper`` instance and not the layout itself. This API's basic behavior consists of selecting the piece of the layout to manipulate and chaining methods that alter it after that. Selecting layout objects with slices ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can get a slice of a layout using familiar ``[]`` Python operator:: form.helper[1:3] form.helper[2] form.helper[:-1] You can basically do all kind of slices, the same ones supported by Python's lists. You can also concatenate them. If you had this layout:: Layout( Div('email') ) You could access ``'email'`` string doing:: form.helper[0][0] wrap ~~~~ One useful action you can apply on a slice is ``wrap``, which wraps every selected field using a layout object type and parameters passed. Let's see an example. If We had this layout:: Layout( 'field_1', 'field_2', 'field_3' ) We could do:: form.helper[1:3].wrap(Field, css_class="hello") We would en up having this layout:: Layout( 'field_1', Field('field_2', css_class='hello'), Field('field_3', css_class='hello') ) Note how ``wrap`` affects each layout object selected, if you would like to wrap ``field_2`` and ``field_3`` together in a ``Field`` layout object you will have to use :ref:`wrap_together`. Beware that the slice ``[1:3]`` only looks in the first level of depth of the layout. So if the previous layout was this way:: Layout( 'field_1', Div('field_2'), 'field_3' ) ``helper[1:3]`` would return this layout:: Layout( 'field_1', Field(Div('field_2'), css_class="hello"), Field('field_3', css_class="hello") ) Parameters passed to ``wrap`` or ``wrap_together`` will be used for creating the layout object that is wrapping selected fields. You can pass ``args`` and ``kwargs``. If you are using a layout object like ``Fieldset`` which needs a string as compulsory first argument, wrap will not work as desired unless you provide the text of the legend as an argument to ``wrap``. Let's see a valid example:: form.helper[1:3].wrap(Fieldset, "legend of the fieldset") Also you can pass ``args`` and ``kwargs``:: form.helper[1:3].wrap(Fieldset, "legend of the fieldset", css_class="fieldsets") .. _`wrap_together`: wrap_together ~~~~~~~~~~~~~ ``wrap_together`` wraps a whole slice within a layout object type with parameters passed. Let's see an example. If We had this layout:: Layout( 'field_1', 'field_2', 'field_3' ) We could do:: form.helper[0:3].wrap_together(Field, css_class="hello") We would end up having this layout:: Layout( Field( 'field_1', 'field_2', 'field_3', css_class='hello' ) ) update_attributes ~~~~~~~~~~~~~~~~~ Updates attributes of every layout object contained in a slice:: Layout( 'field_1', Field('field_2'), Field('field_3') ) We could do:: form.helper[0:3].update_attributes(css_class="hello") Layout would turn into:: Layout( 'field_1', Field('field_2', css_class='hello'), Field('field_3', css_class='hello') ) We can also apply it to a field name wrapped in a layout object:: form.helper['field_2'].update_attributes(css_class="hello") However, the following wouldn't be correct:: form.helper['field_1'].update_attributes(css_class="hello") Because it would change ``Layout`` attrs. It's your job to have it wrapped correctly. all ~~~ This method selects all first level of depth layout objects:: form.helper.all().wrap(Field, css_class="hello") Selecting a field name ~~~~~~~~~~~~~~~~~~~~~~ If you pass a string with the field name, this field name will be searched greedy throughout the whole Layout depth levels. Imagine we have this layout:: Layout( 'field_1', Div( Div('password') ), 'field_3' ) If we do:: form.helper['password'].wrap(Field, css_class="hero") Previous layout would become:: Layout( 'field_1', Div( Div( Field('password', css_class="hero") ) ), 'field_3' ) filter ~~~~~~ This method will allow you to filter layout objects by its class type, applying actions to them:: form.helper.filter(basestring).wrap(Field, css_class="hello") form.helper.filter(Div).wrap(Field, css_class="hello") You can filter several layout objects types at the same time:: form.helper.filter(basestring, Div).wrap(Div, css_class="hello") By default ``filter`` is not greedy, so it only searches first depth level. But you can tune it to search in different levels of depth with a kwarg ``max_level`` (By default set to 0). Let' see some examples, to clarify it. Imagine we have this layout:: Layout( 'field_1', Div( Div('password') ), 'field_3' ) If we did:: form.helper.filter(basestring).wrap(Field, css_class="hello") Only ``field_1`` and ``field_3`` would be wrapped, resulting into:: Layout( Field('field_1', css_class="hello"), Div( Div('password') ), Field('field_3', css_class="hello"), ) If we wanted to search deeper, wrapping ``password``, we would need to set ``max_level`` to 2 or more:: form.helper.filter(basestring, max_level=2).wrap(Field, css_class="hello") In other words ``max_level`` indicates the number of jumps crispy-forms can do within a layout object for matching. In this case getting into the first ``Div`` would be one jump, and getting into the next ``Div`` would be the second jump, thus ``max_level=2``. We can turn filter greedy, making it search as deep as possible, setting ``greedy`` to ``True``:: form.helper.filter(basestring, greedy=True).wrap(Div, css_class="hello") **Parameters:** * ``max_level``: An integer representing the number of jumps that crispy-forms should do when filtering. Defaults to ``0``. * ``greedy``: A boolean that indicates whether to filter greedy or not. Defaults to ``False``. filter_by_widget ~~~~~~~~~~~~~~~~ Matches all fields of a widget type. This method assumes you are using a helper with a form attached, see section :ref:`helper form attached`, you could filter by widget type doing:: form.helper.filter_by_widget(forms.PasswordInput).wrap(Field, css_class="hero") ``filter_by_widget`` is greedy by default, so it searches in depth. Let's see a use case example, imagine we have this Layout:: Layout( 'username', Div('password1'), Div('password2') ) Supposing ``password1`` and ``password2`` fields are using widget ``PasswordInput``, would turn into:: Layout( 'username', Div(Field('password1', css_class="hero")), Div(Field('password2', css_class="hero")) ) An interesting real use case example here would be to wrap all ``SelectInputs`` with a custom made ``ChosenField`` that renders the field using a chosenjs compatible field. exclude_by_widget ~~~~~~~~~~~~~~~~~ Excludes all fields of a widget type. This method assumes you are using a helper with a form attached, see section :ref:`helper form attached`:: form.helper.exclude_by_widget(forms.PasswordInput).wrap(Field, css_class="hero") ``exclude_by_widget`` is greedy by default, so it searches in depth. Let's see a use case example, imagine we have this Layout:: Layout( 'username', Div('password1'), Div('password2') ) Supposing ``password1`` and ``password2`` fields are using widget ``PasswordInput``, would turn into:: Layout( Field('username', css_class="hero"), Div('password1'), Div('password2') ) Manipulating a layout ~~~~~~~~~~~~~~~~~~~~~ Besides selecting layout objects and applying actions to them, you can also manipulate layouts themselves and layout obejcts easily, like if they were lists. We won't do this from the helper, but the layout and layout objects themselves. Consider this a lower level API. All layout objects that can wrap others, contain a inner attribute ``fields`` which is a list, not a dictionary as in Django forms. You can apply any list methods on them easily. Beware that a ``Layout`` behaves itself like other layout objects such as ``Div``, the only difference is that it is the root of the tree. This is how you would replace a layout object for other:: layout[0][3][1] = Div('field_1') This is how you would add one layout object at the end of the Layout:: layout.append(HTML("

    whatever

    ")) This is how you would add one layout object at the end of another layout object:: layout[0].append(HTML("

    whatever

    ")) This is how you would add several layout objects to a Layout:: layout.extend([ HTML("

    whatever

    "), Div('add_field_on_the_go') ]) This is how you would add several layout objects to another layout object:: layout[0][2].extend([ HTML("

    whatever

    "), Div('add_field_on_the_go') ]) This is how you would delete the second layout object within the Layout:: layout.pop(1) This is how you wold delete the second layout object within the second layout object:: layout[1].pop(1) This is how you would insert a layout object in the second position of a Layout:: layout.insert(1, HTML("

    whatever

    ")) This is how you would insert a layout object in the second position of the second layout object:: layout[1].insert(1, HTML("

    whatever

    ")) .. Warning :: Remember always that if you are going to manipulate a helper or layout in a view or any part of your code, you better use an instance level variable. django-crispy-forms-1.4.0/docs/faq.rst000066400000000000000000000121611221066745500176530ustar00rootroot00000000000000.. _faq: ========================== Frequently Asked Questions ========================== .. contents:: :local: .. _faq-technical: Technical ========= .. _faq-columns: Displaying columns in a boostrap Layout ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Of course you can display form fields within columns, the same way you would do it in a standard bootstrap form, you can do it in a bootstrap layout, see an `example`_. .. _`example`: http://stackoverflow.com/questions/12144475/displaying-multiple-rows-and-columns-in-django-crispy-forms .. _faq-general: General ======= .. _faq-why-use-it: Why use django-crispy-forms and not other app ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Well, I'm obviously biased for answering this question. But I once `answered it at StackOverflow`_. .. _`answered it at StackOverflow`: http://stackoverflow.com/questions/11749860/how-to-render-django-forms-choicefield-as-twitter-bootstrap-dropdown .. _faq-when-started: How did this all get started? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In December 2008, while `Daniel Greenfeld`_ was working for `NASA's Science Mission Directorate`_, his team began to use Django_ and Pinax_. There was a necessity to make all the forms in Pinax `Section 508`_ compatible, and the thought of going through all of forms and rewriting ``{{ form }}`` as a block of ``{% for field in form %}`` with all the template logic seemed like way too much work. So with the encouragement of `Katie Cunningham`_, `James Tauber`_ and `Jannis Leidel`_ Daniel took the Django docs on forms and combined it with Dragan Babic's excellent Uni-Form css/javascript library and created the ubiquitous ``as_uni_form`` filter. After that, fixing all the forms in Pinax to be section 508 compliant was trivial. Not long before PyCon 2009 James Tauber suggested the ``{% uni_form form helper %}`` API, where one could trivially create forms without writing any HTML. At PyCon 2009 Jannis Leidel helped Daniel through releasing the 0.3 release of django-uni-form on PyPI. It was also at that PyCon when the project moved from Google Code to Github. Around January 2011 the project wasn't very active, Github issues and forks were stacking up. At that time `Miguel Araujo`_ found django-uni-form and loved the concept behind its architecture. He started working in a fork of the project, trying to gather some old submitted patches. Around march of 2011, after conversations with Daniel, he got commit powers in the project's repository, reactivating dev branch. Releases 0.8.0, 0.9.0 followed and the project more than doubled its watchers in Github. By the end of 2011, Miguel and Daniel agreed on the necessity of renaming the project. As uni-form CSS framework was not anymore the only option available and the name was confusing the users. Thus django-crispy-forms was borned, named by `Audrey Roy`_. The project is now actively maintained and leaded by `Miguel Araujo`_. .. _faq-how-fast: How fast is django-crispy-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Performance in form rendering is normally a nigh moot issue in Django, because the majority of speed issues are fixable via appropriate use of Django's cache engine. Templates and especially form rendering are usually the last things to worry about when you try to increase performance. However, because we do care about producing lean and fast code, work is being done to speed up and measure performance of this library. These are the average times of rendering 1000 forms with the latest django-crispy-forms code in Dell Latitude E6500 Intel Core 2 Duo @ 2.53GHz. In production environments, you will want to activate template caching, see :ref:`install`. ===================================== ========================== Method Time with template caching ===================================== ========================== Plain Django 0.915469169617 sec ``|crispy`` filter 4.23220916295 sec ``{% crispy %}`` tag 4.53284406662 sec ===================================== ========================== .. _faq-python-versions: Which versions of Python does this support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Versions supported include Python 2.6.x, 2.7.x, Python 3.3.x. If you need greater backwards compatibility, django-crispy-forms below 1.3 supports 2.5.x, and django-uni-form 0.7.0 supports Python 2.4.x. .. _faq-django-versions: Which versions of Django does this support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Versions supported include Django 1.3 or higher. Versions of django-crispy-forms below 1.3 support Django 1.2.x. If you need to support earlier versions you will need to use django-uni-form 0.7.0. .. _`Daniel Greenfeld`: http://twitter.com/pydanny .. _`Miguel Araujo`: http://twitter.com/maraujop .. _`Audrey Roy`: http://twitter.com/audreyr .. _`Katie Cunningham`: http://twitter.com/kcunning .. _Django: http://djangoproject.com .. _Pinax: http://pinaxproject.com .. _`NASA's Science Mission Directorate`: http://science.nasa.gov .. _`Section 508`: http://en.wikipedia.org/wiki/Section_508 .. _`James Tauber`: http://jtauber.com/ .. _`Jannis Leidel`: http://twitter.com/jezdez django-crispy-forms-1.4.0/docs/filters.rst000066400000000000000000000020011221066745500205440ustar00rootroot00000000000000crispy filter ============= Crispy filter lets you render a form or formset using django-crispy-forms elegantly div based fields. Let's see a usage example:: {% load crispy_forms_tags %}
    {{ my_formset|crispy }}
    1. Add ``{% load crispy_forms_tags %}`` to the template. 2. Append the ``|crispy`` filter to your form or formset context variable. 3. If you are using ``uni_form`` template pack, don't forget to add the class 'uniForm' to your form. 4. Refresh and enjoy! Using {% crispy %} tag because it rocks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As handy as the `|crispy` filter is, think of it as the built-in methods: ``as_table``, ``as_ul`` and ``as_p``. You cannot tune up the output. The best way to make your forms crisp is using the :ref:`crispy tag forms`. It will change how you do forms in Django. .. _`original implementation`: http://code.google.com/p/django-uni-form/source/browse/trunk/uni_form/templatetags/uni_form.py?spec=svn2&r=2 django-crispy-forms-1.4.0/docs/form_helper.rst000066400000000000000000000213311221066745500214050ustar00rootroot00000000000000.. _`form helpers`: ========== FormHelper ========== What is a ``FormHelper`` and how to use it, is throughly explained in a previous section :ref:`crispy tag forms`. .. _`helper form attached`: FormHelper with a form attached (Default layout) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since version 1.2.0 ``FormHelper`` optinally can be passed an instance of a form. You would do it this way:: class ExampleForm(forms.Form): def __init__(self, *args, **kwargs): super(ExampleForm, self).__init__(*args, **kwargs) self.helper = FormHelper(self) When you do this crispy-forms builds a default layout using ``form.fields`` for you, so you don't have to manually list them all if your form is huge. If you later need to manipulate some bits of a big layout, using dynamic layouts it's highly recommended, check :ref:`dynamic layouts`. Also, now the helper is able to cross match the layout with the form instance, being able to search by widget type if you are using dynamic API. .. _`helper attributes`: Helper attributes you can set ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **template** When set allows you to render a form/formset using a custom template. Default template is at ``{{ TEMPLATE_PACK }}/[whole_uni_form.html|whole_uni_formset.html]`` **field_template** When set allows you to render a form/formset using a custom field template. Default template is at ``{{ TEMPLATE_PACK }}/field.html``. Beware that this is only effective when setting a ``FormHelper.layout``. **form_method = 'POST'** Specifies form method attribute. You can see it to ‘POST’ or ‘GET’. Defaults to ‘POST’ **form_action** Applied to the form action attribute. Can be a named url in your URLconf that can be executed via the {% url %} template tag. Example: ‘show_my_profile’. In your URLconf you could have something like:: url(r'^show/profile/$', 'show_my_profile_view', name='show_my_profile') You can also point it to a URL ‘/whatever/blabla/’. Sometimes you may want to add arguments to the URL, for that you will have to do in your view:: from django.core.urlresolvers import reverse form.helper.form_action = reverse('url_name', args=[event.id]) form.helper.form_action = reverse('url_name', kwargs={'book_id': book.id}) **attrs** Added in 1.2.0, a dictionary to set any kind of form attributes. Underscores in keys are translated into hyphens. The recommended way when you need to set several form attributes in order to keep your helper tidy:: ``{'id': 'form-id', 'data_id': '/whatever'}``
    **form_id** Specifies form DOM id attribute. If no id provided then no id attribute is created on the form. **form_class** String containing separated CSS clases to be applied to form class attribute. The form will always have by default ‘uniForm’ class. **form_tag = True** It specifies if ``
    `` tags should be rendered when using a Layout. If set to ``False`` it renders the form without the ``
    `` tags. Defaults to ``True``. **disable_csrf = False** Disable CSRF token, when done, crispy-forms won't use ``{% crsf_token %}`` tag. This is useful when rendering several forms using ``{% crispy %}`` tag and ``form_tag = False`` csrf_token gets rendered several times. **form_error_title** If you are rendering a form using ``{% crispy %}`` tag and it has ``non_field_errors`` to display, they are rendered in a div. You can set the title of the div with this attribute. Example: “Form Errors”. **formset_error_title** If you are rendering a formset using ``{% crispy %}`` tag and it has ``non_form_errors`` to display, they are rendered in a div. You can set the title of the div with this attribute. Example: “Formset Errors”. **form_style = 'default'** Helper attribute for uni_form template pack. Uni-form has two different form styles built-in. You can choose which one to use, setting this variable to ``default`` or ``inline``. **form_show_errors = True** Default set to ``True``. It decides wether to render or not form errors. If set to ``False``, form.errors will not be visible even if they happen. You have to manually render them customizing your template. This allows you to customize error output. **render_unmentioned_fields = False** By default django-crispy-forms renders the layout specified if it exists strictly, which means it only renders what the layout mentions, unless your form has ``Meta.fields`` and ``Meta.exclude`` defined, in that case it uses them. If you want to render unmentioned fields (all form fields), for example if you are worried about forgetting mentioning them you have to set this property to ``True``. It defaults to ``False``. **render_hidden_fields = False** By default django-crispy-forms renders the layout specified if it exists strictly. Sometimes you might be interested in rendering all form's hidden fields no matter if they are mentioned or not. It defaults to ``False``. **render_required_fields = False** By default django-crispy-forms renders the layout specified if it exists strictly. Sometimes you might be interested in rendering all form's hidden required fields no matter if they are mentioned or not. It defaults to ``False``. Bootstrap Helper attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are currently some helper attributes that only have functionality for a specific template pack. This doesn't necessarily mean that they won't be supported for other template packs in the future. **help_text_inline = False** Sets whether help texts should be rendered inline or block. If set to ``True`` help texts will be rendered ``help-inline`` class, otherwise using ``help-block``. By default text messages are rendered in block mode. **error_text_inline = True** Sets whether to render error messages inline or block. If set to ``True`` errors will be rendered using ``help-inline`` class, otherwise using ``help-block``. By default error messages are rendered in inline mode. **html5_required = False** When set to ``True`` all required fields inputs will be rendered with HTML5 ``required=required`` attribute. **form_show_labels = True** Default set to ``True``. It decides wether to render or not form's fields labels. Bootstrap 3 Helper attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ All previous, ``bootstrap`` (version 2) attributes are also settable in bootstrap 3 template pack ``FormHelpers``. Here are listed the ones, that are only availble in ``bootstrap3`` template pack: **label_class = ''** Default set to ``''``. This class will be applied to every label, this is very useful to do horizontal forms. Set it for example like this ``label_class = col-lg-2``. **field_class = ''** Default set to ``''``. This class will be applied to every div ``controls`` wrapping a field. This is useful for doing horizontal forms. Set it for example like this ``field_class = col-lg-8``. Custom Helper attributes ~~~~~~~~~~~~~~~~~~~~~~~~ Maybe you would like that ``FormHelper`` did some extra thing that is not currently supported or maybe you have a very specific use case. The good part is that you can add extra attributes and crispy-forms will automagically inject them within template context. Let's see an example, to make things clear. We want some forms to have labels uppercase, for that we would like to set a helper attribute name ``labels_uppercase`` to ``True`` or ``False``. So we go and set in our helper:: helper.labels_uppercase = True What will happen is that crispy-forms will inject a Django template variable named ``{{ labels_uppercase }}`` with its corresponding value within its templates, including ``field.html``, which is the template in charge of rendering a field when using crispy-forms. So we can go into that template and customize it. We will need to get familiar with it, but it's quite easy to follow, in the end it's only a Django template. When we find where labels get rendered, this chunk of code to be more precise:: {% if field.label and not field|is_checkbox and form_show_labels %} {% endif %} The line that we would change wold end up like this:: {% if not labels_uppercase %}{{ field.label|safe }}{% else %}{{ field.label|safe|upper }}{% endif %}{% if field.field.required %} Now we only need to override field template, for that you may want to check section :ref:`override templates`. .. warning :: Be careful, depending on what you aim to do, sometimes using dynamic layouts is a better option, check section :ref:`dynamic layouts`. django-crispy-forms-1.4.0/docs/images/000077500000000000000000000000001221066745500176165ustar00rootroot00000000000000django-crispy-forms-1.4.0/docs/images/accordiongroup_and_accordion.jpg000066400000000000000000000471571221066745500262170ustar00rootroot00000000000000JFIF``C  !"$"$C3" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?.(*6I <` (m?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ hm?b_ؠ h@ B((([YXʞzM\TQAf xĺ,"1bdTT'8ZB/ƥxSw7G_EcG=2dTt O,I`98\V4Oc/,iO25$ MASB,/ ivܝB[S`$ /I< bBk+z,I'ujyoFG4MVd[VXya0' P?ݩh Ӵ[Fӝ.nؤ[ nCÙsW 5[J4[t n-GlIkIc_m+O-q}ٷEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEgAZl+REPEPW7soF?M7soR[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP[_4nQԴP6ϼg 5EV((?oʥ?oʥ((((ɢ'RvWs<=vv3̮8bgv $WE_4ͭ\Dove6;dh@¶HGE\kz\EH`!k4!P.[y{ݥ0Di"Rǀ)--.f prh`Jp{k>(^>zv7WN4egQNF|H!Zw"8Ɲǧ}-mbg$Ӓv ;@.8k_[l/cilaDf@]IVRGpAv#:khS躀KӣCW |ͧh ]xM׈mu.|aqhGc(ͨ4Lw>ჷ Zߘo{uG=_{_j$nj#2esGV1skүvHroWh>%4^=mky\[G%not H`^L$qFJ(f8W1Ymv;g;q*),|>B0Π0M\be4 ,p6э끓W_vҭ#)J\wc:ľFu7K9/#Y=09Vy// ?YjsMfwsu}]R>]r )|Wq X8,2I%ÙF2#"8^rnOobu4_vP=CW@:Grx]2 ^qjڔP_}O"9xá% s+Qn4ox;#MMߗoeb7]p0yk^76An]? +ux-AA'ᖧ}[K ZApk6,]-\ߔl.rG8s!|X߈tY'2> Sz-YY[yݹK\_؛mE]*H$ts66MbZ{ynZZ2`Ud^3F@yG4f>XxY4mJF<I~e6uVk橩:ޥI{1L-5}6+k,)c$`Ik n[4WM񧈴~C5)dM YFps4fcL VڔO-,|c{_xg2x8$:rhּY{xH4xV}{ɸ|m9'U)5XAs4_GAwkլOo2 "7 d0#"|It@C_O/[YHdX<ߵH蜓ږKو쵼 IUȧVVPA<y\?0vu ݥm%(4LH+*HA؊Woƶz[[bA 1GG>|Ka>Cڗ7^$쎳o[ f7k獘7 ہ  $k_6ѿ=&;Q&t\n`:7.OlZm>!--W&&<c8 oA@;7t.搤13) >V7.\cyrCҠK8/m4HRUgD|bҬWOz|;wqu >I6WD#(Y\(n9=w>wZjwW~[Ǩiwnʒy$:kGJQe^1;:+_^14Ce*iͤow),I'`>3?e^G ɓ|A3'n{ ^_4j_gd"B:WEVm_ؘ4J[HQd&k"1S5NfNWXԦT0Ur:WOD}EGmoRO$(g }׀%&EPEPEPEPEPEPEPEPEPEPEPPjZAK@Q@Q@^ǤͿKQ^ǤͿK@Q@Q@Q@Q@= P 🇿>:j6`6դv8Nsz>x+P@ҧ.V#\ysPf֐?xFyŠ:^KR$Ċ.%X`ptS[ymY\y"~_|Wu'NִV;)l?B AvV j粏MwifHZ2һ`Flv z|?چ1Az$f"Tc8RpsmQCpZlcxc'MtMq%ҕ]Hvگ|3u-ޞkhUcGF ء~R23*(z Ft14*[#3mIffbYIbI5/ZͽΗ[y UY J)9h-px¾J@DrD]B#Gu)rR w0Sgz%m*etX[ .vyY(ƒnQB`zrßkWw:$^NBho >7 +Fš՞i=ut!1ʊ>\t(Zhnr#yyiynR%$F#v^1[z5Ə[  ,{ra AW裥C:tOKk{]UUoef,kQA8T .ogt%v BtV ;Fa``]eu-?i~!=FAhFl.l,eA#~:X:o~x>;%R$pslD̛F kwZҬ5e[h H<2CxS<+i󟋟7ߝ8⪏xTk +1k}_$LQ,HA?8]VErW uoc11X (UnPm")0Og:/mZ-A.HU8u݁v,2ڣ'W@5[Ļ,dK;cɛobsZtR[G>o Gi,^]&%QRJ[r!b6F1i>*H'\0=,;O$U8[FIFgg-p灎+KHmaBoY$IhQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@A?j(?]-QEQEEy6U-Ey6U-QEQEQEQEQEQEQEQEQEQEQEM,;Cif.ZlyıP ۓڲ=MRDɸ@Ud۸=Uq@ejlv%/# 'ʔ9F\^w#Ck4/8 $IhjGJIvgG>xYifdoY,<k(5?aZa=NkiC"$P^wsѳCsGnl|Ae\hׁ-q˨|V$QNO=SW:+o]Höˈb*`9_o-o[|/ӹ(5u)HbWPHKyB@>傌n)]7]k-hw6}RY 0G8[ᶅzp\:u+hoi"ة ucw#M>h3muopozQBA%UU2iz"4`k^<\?|:/7du !01}NSͤ^kFFl\F|g#<2;ij/tXI5CV x"?5sh~%·{-0N0Y#e`H#!At[E;ky߈%M>M,ķ1$KIr)׵~-ݥh.!D[[yV WR (sQsjZ֫qsww6p<ț?{P~Pz%U΋lmm%N0#*~K M?|s~&Xڮmݔ6ױŐI9By*JgqXqs|W{g6K<goK+WR8f OzhQ)#[&3Vv,~31$(~z[o5jL[[+)b †$/|'}}?onÍç:4&~W$X2dc.Y~ta߁]wAVe%dIԠkUZ&bއKN}O> Ԯo4fy6R%Porwn~Vz6{F21$c;U+]_olq~4_F-`tY %ȇtT?7> 6EC6x/ 1),R7 ncD?5]i>&maYlд pGQ[p=V}WXL0,>O0Fx)í'Jjz官iWW XRC6ym]-ݿ%w|^~V'sL%oz n8ŗz-m<7xVU)-Ρ<QqJgsFe𭞏hjG2ΰ!F]r7Qþ(LV7ΧHH>LFBӁ+~լ iať V:U.PPD3 (]oޠnj= TaCVv6Hwǽpv/6s=ݛ 6(Q$WB 5;5 ZX Np[qH%1婎o+smo[" 28$8ZWn*^Vڱ]ʋ-%yR6\`9 𵟅mo/^.&^FUBc``j~v]/ѯ~/Ki6F]/mŴ]1),R7 nS~L7_H kF{ʘ%v5L]Z ]bKm2d{hfpay|g*3M~=ݛūw6zzȺuʵpTC6]An}6_5}3^ *^It9V\&Kz)0صΗiEyC,ۀ6cl|j0ҭ,J{m94'^3d[ Xn8"jzƋ4pdԐu$n򴷢?nRעռa>4d4hhdan=6&x-mYxĦu%}()f ]8'#85ԭm~^S jјB5SiCIM7Jk?;}w7c;]{b9) k)'՚(YHYy'?nUiiUFp>e2n0MoOSGHesrAֹp.i}+P>96+qפ/ÖGFhӫU|*9<5Ϳ_ 5ڱ1GMPЭ#(S31;?QzkIq )V |6{dgt&ןYkpԊ]h61;v9U i$zRY}vnJ;)7߂(m_\/sq/E]"]5$\&"8P~* &MΚTEE1vB\" wsq޺nt4MF~IQmx䓂&yzka^ >l;-h6W}oGv![kUDo`+[;ibgV{W( |5S]VxjVf$7XE8{]JCC_ᦓumkWVtY'#HJ͸IH_|Qη\Kyu4fSy ('''<_oVK_Ցiuy$ΖڳX XkD%18 Lpn Lj7Th}qgR4?3o :gKULZΣ*->[y|mߍ63ttu]GV _6Q~ȷ$2%۸mJ^OӥIoZ_麦z9c`Nfg#Z:'Y֩I7k 'fHePL:!? vwJbKW1#jUG9rykGuWVsGi Ҭnܥ~@3aIQh8m[%# ^2ΑmKZ] ":K[iwZLaycf&C)ra\[^-|1kP)J9|,{;b;.ch'ׯiLEassS:mpX BV[cquAkwg̨U`(^0Ua|#'$񋖒vK[_|g/ A nnB,$T$U- KppxVυAVe%dIԠkUZ&bއ~_éz-ޛ& 2ǵrђkQ\}O{԰cfF$gvc׊Ku5߻[_{_]ߊ- qѝ&+5~Ȑ#..wu)氭<{KnxrYo,Hec :&Yդ!5{aivtiU_r6eqӼb.!W#-vgwI'aߕ~s}7WVwmSүoYaf_)˶z)Nƥ.?U}>[dKYԬ(%A㠮f_bdni2reqռcnB7 BpEu]ihcaK!T` O}>[k4QEIAEPEPEPEPEPPjZAK@Q@Q@^ǤͿKQ^ǤͿK@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@A?j(?]-QEQEEy6U-Ey6U-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEEV[?t ԴQEQEaݍ>Q7WڶSǤͿK@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?O_ Q@O_ BTP_BW=*EU=*?OQ@Z~Wɻݻ{楨[?t ԴQEQEzM\TzM\TWh#5(oZ?j7mRX܍9 {b9+21WxgڦK9IyX0!H${pnoܬ3V~wVwK>2-Gk|7n]v 5#l:Z:}swݷnxsv M7rDhMo!0ǴrvZOE[n7&)WoV#~y%O ]|®-+WM6sJ񦝨]Ķ:cwbN1Y7-̚]ͅ~c!3#O*8 mSE!Դ_F6]ٽ];r#l9Hdr NJjܯgmv&o]_vފ^[[Bޕ3SK=# *Ȏ `͌`<3k'{4R{H"#ݘc䳅QA'_ kdnaqQKy%N.nX;l 1J29oA<1am&uZ"zN40~{)?HW}mVW߬_д-RXc$]da؂?JXgѴsow4s]<7d]p>\TTچǩEN{QYQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@A?j(?]-QEQEEy6U-# an%Uqʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(% ʓ~e(~e(l+Rbc]I'iQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEdjango-crispy-forms-1.4.0/docs/images/alert.png000066400000000000000000000123371221066745500214410ustar00rootroot00000000000000PNG  IHDRW9UFsBITOtEXtSoftwaregnome-screenshot>rIDATx}p߾hՋeٲ1wBBh4i6urL/I﮹fq􏛛dJ&W+R/A##۠ -,GVC~- bQ؟F4".@PP#TU @1BPP#Tňg#MxHS^ 3zN/fwh%p,fGQ̇Nnp₻DT7KI"Su%vFD*HvEci">2Ŏ~gN)ۚ'o^Y;pw)'Wm~g{ckow]7t7#RcgG:#lx_z'^AH oa&Rw_FsD$E9w)coXX6d7Ƽ}G;Bg7[R_QM >SaE ]/7UOБwǞYs}׼_$+̯m2R1|xjj/E"I0XTRIvN#W]"e 1镉.=<&;$W?JHM?۴%VP}cm7.xh$+k?W*NaA(%y{&l[EK4doidϻ{܆{l{W 7=Nu{6>5tĒ}C떵Bfe0ZZu3Ǔ2xZ ebs0IF2ηdO;Dۮ=a_[879f5#ݶ )w?Ѷkwk?"i'L&Ã3l?/R*$p$8NW_-wW#ׇcDTr-Ԋ-w<`X^=j;sTe2"J"fjp8Fd߾z/-%Yۛ8*ܧ2v|tkaw& Q:th@jnܲ"ȃ8<$*Ls%bgFZ%"6ɨTWekyŶtg˦Nt߮XqTn\Ѣ} ҡKԲ'-SQp%!"5rjXZj)rc/g±:hH9p~)5u7޵aWz:[KUbeKG iJ ;5Ӭ7mjNKcɴDrRSVS=mИБa垦-J\i71,]( ѵ7# _msTFH&*[cr VklU-K`e98,FE$"RXUzL*D\ek*9jK&V"bP^lXn%"U~|22)^ֆ%cR%rW%_rrD¥xՔ$"Ғb(E}D%5E)D*$  \ \FGj655bc] \3xscޫ@V[K}I "2y҄f{|w"5cċZ>c55z_嘚{|eF( uU0D+ʗ.ng[oz" YMU7<3}'ce]Pٞ;L,M_oQ !aYGZh0^N r/>Uhz-t 796DN[ܝbwdpV| hpY3J/ 0vhИqp0]1<c5gjyZ3tAek4~b^f1"S?_W|ZvlH Hz_l߬OSҤ5g<|5;DCt8̉{?|oL!9S~u+g_q C!óHD!hU#vŁrZҲt 7.MJG'Yb)t;h[ IRJV2R29dϰgiL*]C3sj ii*%g"a MgR9h Z\_(㈈eg<.xRWZa$"R q [N$gqw $4ߟxBOSKCpɾ#yS.)o\"xvTj |3wɕ@,_IFqTme%ęxP$V!u?Ă_>kV=7hq ikXN1Z:sG3]ɄtZÝnr3 E/vJSklHHp⾾P;"|`0888k[Y;?zl82Ft6JuYV1'+@Կ?9_G/ IsIi7Z/ "ù˝t3L\c?J):DBC$"V~!3WOTʿ^5m!ޛ h\g%}{}a͕U7xm5OmyB2|u/{~B$Ԕoa'r[o|nɲja 8^ZQ.$>l[WrLrڴ|={[ +wpOow8H\x@91AI1_uqUmÒi?|W[?u\8@\#+7^0hmˇL;>YЬ55m烷/H35KC7/g~YUhO/o_`k<7fF/v^k7Ց_/a.'J_d^Ȗ0 %4ep%'keH%-1fTM gp"QJS$""ʰ»ZxaVGn-X#TRcY$'~/ODD)M:*h iMc33oD N4'K*Yؠ,19QEY9ģZ6Z. -_!8F3ӚXSFF6~zt{6PW]FFluNLZPVSflИ9O ea."ԍw/}A4*W?ZG9q QXמpnX+[>)}=o|tJ2g_ܿ”ם‹-~0q_Rfq23ݲSZ$ "X^Tr"E-#pC@1BPP#TU @1 ԈT`QEc xU ۴t~]DSR g٫@tJM%5 Hi J8'fwiC`EFcxpVRH^U |ab* (F@b* (F@bJz'IENDB`django-crispy-forms-1.4.0/docs/images/appended_prepended_text.png000066400000000000000000000023551221066745500252030ustar00rootroot00000000000000PNG  IHDR)sBITO pHYs+IDATxohe'.5\;s)"V Z1L+ 2e芴/ھX'͊\AcҽmpIchI%w.y|:w:>ŗyx!`/փXXXXrV !+++|~}}_n|>0PphغGb 4ve4lV$9 JjS0eeeBӴ EQvBRT(Rgk)k[q:.1Nִb *%sA)L A A 5NOn휜Ock&b:5HWKsT 755n힌[xӗƒ/|ű;- G~+!hgƿ>Sf2k|;J=ƳuIQv !0#3}a{烻6=QqtH]7ñ*B~K]"7ځpQ@'%T*Ȣ\Y$ĚuOBbO.-/߈6D,pn ^ͭ?dguZ}ڛlWKyZ3"BQ< aAԬgb% 6hm>]:;k!R Ÿpju31,ow(`#BTBŧgGHTQZXׇzݛwY\%Fy4Ƿ=pb~=ͺ~c'Ϯ2: ر *o9Oį=e#E5a۪ٱK?_Y6RЋ!DJ^x@QuS95;;[}Nv>zJY RX,[[[ vYdAiDr>! !b_,DTq"<j}==` \ BJ׽z<^4N׭߽cےI0BU38r-0D U wCsw=c~M|2zɔJ y)#ɒJ?G#b%hh-}(~dX,F_%|WYejiilHz4(@ =P[k봌IENDB`django-crispy-forms-1.4.0/docs/images/bootstrap3_horizontal_form.jpg000066400000000000000000000370751221066745500257300ustar00rootroot00000000000000JFIF``CCX" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?((80I uWW'e\M}[|% % Agh/ŭ|AŸsGG?h 7xú;OxgėzGc]ƻ<S̸-w#/ |C6 <]uA[HUkAJaĊt ~XFu;75KkSqxQx{k~%!+6jaH906 q巴9]NmJͻZZROt>NVUJޔcdo?au_5Zx[+ ËwV><~%kP5ejCX^/m$?M3Lտ:]xv R/'→5(cOKMao sm-n#㶵"V[ij|:Zi HK4'i$ x%v{,|?^<+OxjG]>4?I\-\i}ͬ^jKG?WW7Gڮ%(T!OAJ*sv^<ϻ^:&nĮțQ妚¬n)?8.ׯT*(lnB{힔>ߧ/X䵟# X'' wYa)dHúG"KFʬFC+{[;|K& k [}<Q@PpqgZY^wgwVqG=ͼS[[LMsC*HUQIm&p>Z/&gִjo,GL%t[+ílmuqDnD6٬coq-}r M nK}a9b30NqFѼ &wxZI m"/-l]D[wq2#IZ_ S$ɢ2j "I2_ѭ$]R@I[N5mwTuMzO>0iK jki֑O%Cix]Ԣ-sgm{HEmL~aeo"< W?m_ً ? xb#-M2 `k-CFpHYQ6*UU@**BlPp0eU-=4սBۧz?y5v=5P{*}G槯?Ə5=Q4$SGO_jzhJ*?5=Q4y (G槯?ƀ$SGO_jzhJ*?5=Q4y (G槯?ƀ$SGO_jzhJ*?5=Q4y (G槯?ƀ$SGO_jzhJ*?5=Q4y (G槯?ƀ$SGO_jzhJ*?5=Q4y (G槯?ƀ$SGO_jzhJ*?5=Q4y (G槯?ƀ$SGO_jzhJ*?5=Q4y +d~jc+S\I˝^G>XƏw 䏓͸2 <uO7*O?Eԁ8<=i:rxsZJ2M7.]i%1A.I/J5I]xmr=遧o D4_kT FB7?/oo_u@hG.(CEO?qYgHsoWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.(CEO?qYk#x=˪?(?F'x{To D4_kT FB7?+soWu@hG.*叇6vs;!ϼn2TIs]\$N4k(BѣV%$#;S.n#KTZD3"E5>r(ޯgko_J񦭭xCK_V_i>B@<qzL[ZOھcZk Z߭đR(7~Ғn)s4Tb{s%S^\ozO=MH>wx5O |AԤ}GΕvVm[C״SG-"%Y_֬1&ԵZwj!i^2 Wie:v87i"DUbͅl~_Jߊ;K>?f[QsL?z }/W*M~Ht)l%%VU޷{6ZG <(?jˉ_|<>kCũo 6h2࿅ 1mNWŞQ/]o/|#;r[\|?k߈4dנXʹi7K7RrUMF1XܪSvTJV5eW'2}AOzTTLV^A5xfYiusogmu᥸:Wvͥ}9n.`F2B N/#/MxA>/ռ48u7g6r6@I}O/˛? ~?-3kzwω/7ƞ_a0_Z-4Katkyg/_ 2 ~_ ?gĶ9 V0mO6OũxA}w#K$%桩OTyBrJb9\m:񩋅wpҪ8_tEY8BFi*wj׼Vѧ~' B09݁c$IYޏ~P>&_马iawz--o,-n.]8"4yH  GC"d!ҮT7>RE:[wXnZ)?uͧ,&|:ëY?&fO @C_xZViYKV3ܔK8aq~:i?ĞN,;ɯtKk,Hmo[\^ >E02T;86ӻ*VMMVounGxx%u0l %շR%hLRMfxw_YMw>".;}隆Y,K%ؿ~ #4ͺgjmcm~޾ y:|4N.-ޥymPdWF5[^%5 Ky[8<1~oV1]_]5`dm$M)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW##X?o~W'տǨPR\ r3E+1E:x$vIԔRji?QAQpr\tv'A'_z]P(%E$>88zr"TmVh_Z+5][o٥FtgRQE $Heomv[[z[yvP⻶xX y#ul@pXh9׉sK#3uS~c%A\G1^?VOs.[E+[].z 6Zh뜗$(+YQ b<zguS}՚Ng}-ߛ,}K ω:QI_r\е\еutS%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,%,9OHZ?YʏHZ?Yʺ(%,5hzo9%ѬR츒VB3sa9y y󎣱?EPEPEPEPEPHxk8xY&e\ޣ}.-r *kh{k*gLcY 1xRxZY&Vw͍֚͹ڶ ,6Gy'tP.=z +]nz'vFs׌޿2nO?<#Gci9iվ!GN-[%CT*i4V(B7Vu४TrnDP&OX҄ƣ]ʭ8ݓ߯aA;q܎899?Ȼ(XOٯ“67#_ٓkzl_.KM Ŧ2Wcuc GCHa.]ۇwͨjZ;RmT{Y8Y;r%yI—q xgJx^!ռCU~]W◀|) ?^3~O?|1imxn-F_l|B/JQv Y~Bo ZaN<, |kjzw&:xkLk,缶[KMpԜ*-k)tNЭRMSm=SuٹE7n?18vc'+&)4 }?sxZw3𷇼a.ZOuV<-uO Yx_oO5bojGiǩ|xM|F OxF<#7ĚVe}_j_5Ҏ֓hzMǛiF-JJrqeHn1MZ[R^?!sKLQE ((((((((((((((((((((((((k1EO( ( ( ( (nO ӧZq-N[8;8^J>R{ I9$ߚ-E6NwX&s/e_FM6_oTϔ n'Ҹ(֡VYF6j|Ɵ{xT]o Mx:!oj*,=]V-8O^i~ǩמցǜE(Ǒ%nT‡.Ii{X乛漓o^yKsz9IOW}ϔ-~; m=kx`ռ&㯈!,υέk,W|5xInQ,2(XtB ƫleK-n^Tqc҂I<Խuҕy%RWM%yW4n|wx/ujZK:ƒ4[U YNi[Z#׼/=EtN%uv6i =$hV/j䗺uk׺jz{wZ{s5I#̻g:y/'6o݌Ѷw{+/ *QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5?buQ@Q@Q@Q@Q@,0=ѴiզHL:L<)B04 Fy?nr1S2W@|r./}?zgÛ;ߍnݹѼHxVT4^ukq֒VSYԛ[J4mzwkmm~ӏ hdMxĄミ R h#9XO8Qc_~>Xk|~}.GnISԒwJ1NQqNMٻ[)8)D&rr@Ĺ8 |H#4Z!$z|7|a:|@=N'x >%ҵd]ঽtmMj&kww댩k4/~&GO[|4'_|!牼MesX5{]^~H6ZkǨˡ%q56$/kёR) %{N09kZ֚#K6v}auCsggss k>\4+Fjۿ_i=Νaq %ŝ:a$aoYz隁A99<hh eS_vnf^i4QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5?buQ@Q@Q@Q@Q@Y|IBǎ3`6$=jKlo4NR,^)g)WTwIQjlF$a,$rhdFHu+|Pmp8ܼRc$Ԓi~x?cٗ >Ե/ˤv Q |/Ѯ4K+ߊtw[hP*τLwp#( ( ( ( ( ( ( *;)vf ;Pk[_o"-QU|G}m%m:ư Hh 13€1߯&:'nEPEPEPEPEPU$ſ{GVꤟy(:9#$ѱV1[I":ҥ,fh`]$b:d#zm=W ۟sBbЧ<&}g^./ 3?qU x,⵳.)m9oMn}[rwFB#oopz;[\z+m .MP׎: ;' 1I< MաԢ^`ܤJLLLF2Wd?C)we^'dݕCh!(Ig-fh0Jb7j pAbr7gR.d$<3yIQgg0q~l2G޵5'g/vc֨k u/2X r%Yiqa|rF7 sUiPIAtָ 8=ҷ@ }/ko_igQ^Ocy閶zm:޺ts}][Q:E!YpTʐ o GauydWX8؀9'u_} :+ɵoI(kˈ2Ip̆9U\)A?1.O-C[hѧXt{ۙb%1B@lFNA_=J>loVie60#֮P$艹r֛)]$!Ϡ,FMOK-Q_%FkuYˠ̣r>a\tω~@ԵkM-!ҵtp#c1 gŧ =$iZѸ$e8. !' c‹ _^KS(6o ꖲ|%{Xf0P |h n1Rv~7ѵ}uxu -ș$Jn#o9s,M^_;k[8WH5yGĿxL6mCi*Y 7(F}E/p$H@lnf?7ڧmGڧmF46bW%pU Lgt.m6H7lF+アIڹd u}Gu}G6YYil\0D\: j~633w3V~?n>?n:?nEUT T WS6S6 TU_O@ۯ?.O@ۯ?.-QU~?n>?nMW=b.?/ JI<5"s t,Wf8ʤ$3GZ,U`VbrrO>ϵO@ۯ?.O@ۯ?.)xoFy.m2ۻ͠3^-I5;/fLb09 ?j_]j_]^J^jDFGVNNO gic1%nF]Oju}Gu}GѰt&ZoMǸ5il,ݟ!OndBT T Zmڭ-&3 vڴڧmGڧm@j_]j_]ZQt}Qtju}Gu}G*ڧmGڧm@j_]j_]ZbУT e\$eYnH$q#PΗ=̷\ҹw\jX8RMOh~p+L鰼9,NqV x_'d)bɸy~Z8 c;Ǿ1ڹ׏k<ڗ[LlnJw(p[rk_-ReMCTTk|Pl@`c^|WENϞ$ms#\w_q;~&dʋO_wͳ~E}&;[KukI.3O3#qׁuP%7nKTuXGpa7!6󴃓#$wIuaԆ I]L>M6mmvTPV_խK@[ReXM&^]Ym\N4_>[P(薞!Nx[.mJ( ϶zu:(VSx+"Xc#@ʜp9jKԵ;յ}I++KH/ Tv2eEn?" q`` =[/"wɼ)8~D>?W5{{cOi.ԤW\o2dL8^Рmasge#I d&eRyCu}Gu}GҶ Z կ5;NI6vߙ\fP^6ؼk8,,qQy#?nw7o%tRk:eYuȂS,\rOC]Ҭ-^6Wccݰ` ong?n^C-U]/=p4xԖQ462ıhj( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?django-crispy-forms-1.4.0/docs/images/field_with_buttons.png000066400000000000000000000026171221066745500242260ustar00rootroot00000000000000PNG  IHDR/R_?sBITO pHYs+2IDATxoheߓ] եT?pes2tvnt([l݆m9ji8'6RduC /64/ڪ+](9r=/wfy}^OrOۇ41g'P&aU0h*4r  \F4VO9U-E!&7Vc~'zha0FGGkjj{"Dbjj*6m䤪'܁R  x >虙;8$h,7hMrrr䜠@4pq4d$Y8*h4⨠qFuA'$ȡƦƪuo|S{b8`(ly~c]^x h4·B':V~qpBcUW/z▮7^}E7{ 拫`7Җ45_4X~JUf+ڏ|A<ʮ> D H,bha4D&.jmUa/%%fA=?68tto{&=DU F !]iXe>ٹ2#o9Z=q^[\m|rz@UY8w64/$YX:+w o; pmhBmZ6 ²UpihBJYȹBNE1VVT,!$T%1ƨyt3)zC,q3 9BV{Z9;1JaJ$ Q%Xxû)tFBVIvv<Jdc[cNHM!fh2WYY){F8B^ s x=I*2_$ t]9HuuuB#+cT*Jsmy à2#3 bM]O?0hd%s8*h\|0hI QAA1ANOOdbJ9A' EQl]\\<00 (UC=t2zj"F +_֘Ŧ{  UU 릹FYȼg~ݢ#`[3`Fp[dH硑`U0h*4r  \o\񍤤QIENDB`django-crispy-forms-1.4.0/docs/images/form_actions.png000066400000000000000000000111441221066745500230100ustar00rootroot00000000000000PNG  IHDRCsBIT|d pHYs+IDATxy\e]j:zBM$aEDqPDQ#zF3AGpܕxP,F@eH@!$tN{WW~}f3i2t9u:u_-{-cADDDDQ """"R1NEDDDb(HP8p*""""ka>'NݵA R]]=1é$%""""'3/""""DTDDDD*©T S """"R1NEDDDb(HP8p*""""CTDDDD*©T S """"R1NEDDDb81\))~q^MI.[8qlk:c fd2+}kb1H˲,k;2Ƙ=zGXܧc,?,^7D<Q( <p6jƲ,1OX۞8 L\.G,S@9@K8{]9NjW'6.=Eg˂cQs󳝜R# v<(bAP*K-"""Ӿl=9N_l /孃d2L4iBQy©TpL>H9.{ AtD #""2%b?e3a< `@P|Xj -[ickc6fz'rKDDDr1YT n{gM3%@6TҖEO@k~ m摻/o%k2k\v;Ie)?}1usSW˩ xVe$MW1@0z lgp++ w<7\66 jF/{[X.3ߕ&6E.]n#u])~``<ޘ5lXo#7y/q7J<;lC]zȗ/OU[-?[pjV8{8 E9pkF0˺9$I%sx/&eNl ]<| GN.BbUN"POIע+\ r,<@t5(|!1ɧ1 !VVV%T4WyD 8xH}4;jbac& lY5d8@S#5v&di B4Hn_ؿ4F~N5TޖSo?f>Adkgj?{%Ouy\O&x;qX)j^ʱb 5L۟M%j[gp8newsJdΛ'wnA3)9z|*eeW`a+ |:7`0zjfK71 Ít WrkI"/1`!ͬoŠnypyYPS_5I|܌Ԙ0̍xfSΝ˽GKYI5u3CL>t7ZÑeŊMܾW:90&Y7 S2o*ΙF<froYvrD5rI?_j9r:pZx?>r:DoOOevh;4w O <ؼ!څINFܗ'[ (v𗼋e8<n[a,l|R |CU4á* _ 0pf{”UM}]ae- _ GFg.ydGȱ q;x4\ɀ׷(tsM{7fOs֜_u[8O USwZ79<,Et/Yu0&w-YK0OtdA0`9)Q']3]u]DCJCHYɑTDD6ɞ޴]DQۚaݐE.WMMƣϝ<-YşCkKmlxr.6sNECu\mEnZ9Lqι#GqR gLKs5أ}e#i_?*lppwn#7 h__`Rk LNќ4\ 7̶<+J\ܖ'ffs |n#0'.ls{v7ݿ.# z{}8u,:ef-lX}[k%#1s8V=lbLF=Sg?JWvV<_pg%W^zb1'7̎xj@UDDd-An/?z]a,^_=c[mڎ:o~n.SW\`c1`yS&wi`J}~B pyempV~nyy*W]6O=Yس€52;<R?.AGaf1IN fͪnNW-Y!n}?߽(n?yƥO5Eg- bٲ睶=>qBZuW~y6q'/dN'ΛW$9zlfGkΠ &1|<~vۯ#PS.>#\tZ/KnOf~|5br*""r{GXܧc=|o w˶GmbJ>Cg q [r%C8d1)x9h:u, ,p]ꨍk! X^@ރx!X~@ҹh̆b@EH/~ B9vV>$O jlD&L'7AeS"iX}ijj΀M@P3oF,, % %X!+0NUPp! 'Dml|J"C.e (=,7L8bRÄ"T*E(N}OEDD@^W3!jL'3ƺӳˊݶ Ӈt'{]gJ;gw/7|9|`q8\5Oi kĖP#50TKczDw|!1`_eGvoq/ f!l |,ptG1WBѣ' t!warpF"J9!.a~LDe EBG, BM,":XeY;F"ruwtW-"""uѰ`á)Ru]yT!\DDD&]Uؿ """"5[DDDDh """"R1NEDDDb(HP8p*""""CTDDDD*©T S """"R1NEDDDb(HP8ac̞ X$"""",kXDDDDtY_DDDD*©TaIENDB`django-crispy-forms-1.4.0/docs/images/inline_checkboxes.png000066400000000000000000000036571221066745500240130ustar00rootroot00000000000000PNG  IHDR+BsBITO pHYs+RIDATxOh2`H`pi@8N"}D)*iV M&>!{]bc6cB{ik5EI$o&3i5ig9͗7gNi`0MB0kpb0W Lpb0W Lpb0W Lpb0W!˲jv;,H#]H&(VtG~XT} (-cii^k8BY ͊[ kB_lCFML&sE :;C2f  Plo!foܸw莗yh/5y/X eMjYA>OB!6?X{Pꩲa բZ߿O#NSZocJk"럖Bl?:vPvy'2矺xȹ&ETdC3[j+B3{Y[rHÇÑf=zhN:%἗g&B1BN IYu+Hq>M'e9} rXLTORMzT)u^ji 2 XLFfT\GfWhm:Jc#oJ^ZKN:^7ikOۍnBa&0Y;;;I~92::fw,rt4@XΒ3Ϣ TLcY edm,S6`4Ҫ` Uz(J>=fmZR\).4FLkW ruB$csS-5ڼm&+ꃤ9*}+krweE;G (g~ GR|8jmǃ/Qi\Yh%J-%A+4 "mԗ> X U r=VVV/u̶ˆmE+o6s1\* h#+Mzu\:* ӈn7р&&KLBO@1Vr9zw,aec6ޘ %B7ʞ1R~5MAmD)W NESNW~mo%ğ9{ȥT>q-wL^vKcV[* …*VVfPOO(HJ,TC퐡 kWs4Z4B߅j46Bݻ*vwvi $c\qFzρ4@itag_&mǡ [!?ܰ][iCcce3+˹s w,oACrla`vfh$эx:@ Bzz\PtNVX5ăs/T<A9sF*e jۖvX* G, N ,U`A6I]('a0W Lpb0W LB٣#IENDB`django-crispy-forms-1.4.0/docs/images/inline_radios.jpg000066400000000000000000000050311221066745500231360ustar00rootroot00000000000000JFIF``C  !"$"$C" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?.+]IJS1bǩsʊ5v6;@fE'>YVP@;{}K)nl3&#wS؅c=NƊxKA/ Y3PUʕɿi7\fAxűK Bxo2 ڍ+e6r!p۽/_ډooL+ĴMgTzcwm"l#!2eڣU$s?5kv0|Mj ١i31YAT SoO] O=.ŷ^khcfSjNYGly1bqƸwKśQ#J Ov"IuF n'OT==KQ}Api氳I.L9ܨ@p qRI"5vmG{ik,i,\e K+CS ֶn׿OEyH>gSUaM"%jaܞ 2O%ſDtrfZfDr ܆y~65\/L*+}JԤ[Tdl":Ff+dnnA/xkڅs]Jy~"IEІiXl&2q@ɥuK_;?߃#Ӿ0kGڍfZ]U%h2NF7qh<_g+jV2ͦ$b&'ͻsW{]ɉ^gmERVI=iKlʏcd` y)PFT敧zE֓%͕f9lAj5qmQlm;G]4,`ԮHQKXsb3ԋ-޿{(sZ3xe!An[nddk(Жu_v"=QM$ϫ%&x7ma# <AfIүlfyke´;Pͅ%F}b:*mߐޮs<i`2ɘ/ayX1Sx¶i:pXH'TF+݂Cм跚UՋ݇ ?2]qtydrɜuPsBITO pHYs+IDATx}L̙;`c'f&0BȬx a"%!/]n6t͒h4%ZEfZ-iҨeFGCb bfה6n|y_pp8 "%w JDrP(AD$JDrP(iNl  B|(R*Z6!!! `JJJrr2G⥍L(CA'///=r\.WJJRGy e2rX-0Iv#YZ#0 {"R&T*&\j&H|Q5Ay"P(AD$w0;Wϟi]u OTڜN,mw; u8mXmZMb[͇}k^y\G𮏯;[>zl8U*r}gg/խxqn3d_}k_9fMC)yC~Ѳu۶Go_7dU7.ooQ" 0k@e*~ˆ1r[js#VdSRQ2ߛsvu;@d fX4vǨLkcxLi.Z5xH.U |Ɗچr#?nsptȭih.T;.vLpDf.,/]_6s#p[KtZIus 5[ Nbw*ݽ*seLUܰ ut;Xrh$f+ oʄ@!nn0Tٺ5Z &_OzJ<4MѴha L3 f7pif |e@ *E H,O5dYr".eZ-z*I њrH>O =k'tU89M0) e x%uTf4 XË޶ӿ19@4RXxa8L;z]b|@4P:Z8X/Q ޘ]w.*o |W]1&倠 kvmpv}uhZ$m}v4,4z5X/KI8WApw){Πq8B]Pus9$sj 2,F#9{w0ʎuObJ!ۘ҈qhdi+]S)б3zɗpqϺ7?TBErLz{>SMpSjT]k5ɱ UrL2]mݎivm2#\rTXp/Lֺ򡑥tIή"oHݴN;n{ꏝ~;򧦧F{&$?SAvtȫ(+ ms<6Wkqm3yHLi,˦#9trW;@(3 *>@Mgח S]HpCT N,9>>^PPn]mDQX,[xmTzyuϏUU=oҦR?[[ssw8XJ !-dyb02co[:wSO|Ԭ=O22/S5?c86i Bq:8GV؏B\ NCA7"9sshi* QԃG19\DHȡt> sajdFF>9,>eYsȪ\!}#BH %"9(P"BH %"9(P"BH6I[n|IENDB`django-crispy-forms-1.4.0/docs/images/strict_button.png000066400000000000000000000032771221066745500232400ustar00rootroot00000000000000PNG  IHDR\(> sBITO pHYs+bIDAThkLW;80D5-b5jTъ&Ei >icնGXk$ `KUZ|(A+By.a3;shU_g=ޙ+C!E<`c 9V%1&r#Gć'O& {Ë|ƙ _/d`8'qER/i BU*,95T!#:8߸tLBna|>h$rɔ&S/7ub2ib-BH'?g.7o8I `T4~&y"7cƬKFmշtA7ߍh/_ѓ2w!z&yS_DDpҚ\f|9eaI_mc4 ,0&CP8VVP3 (V PЃ T|lhv )d5C^h1kھ5SKάY谳/ bfD[~mǖ"W:mAnWVzBn}[Fϕ*ޖ#! +41wEwj%]Wc;bWH?gCx{If֕ F8Rm,kff鑆5;4$Brz:MЕY$~ċ.5/VhyqBʰiV$j Oey䩪 \o(T3p[In>Pj;Ï͏/VEYv~S{  ĉdjj*e"ofԤPD Ut\wڦ#o\Yu}9K 3k /oXхgwVV#97lY{SN 9T$CTgX@_dYU0 ;`tC%wso;hB4+7"'"6NCO"Y-n[: C H. @a[՝a |3DYvlQ}3wIg45ZZ jތ o`0?:EN Š})8S$ʋ7]+5)5{D<6?qɜ]~x^01U ]P ! IZ&Ě8Y{r,I/d,IoCȻfڒ7-03V OYyuuQ@=6-!}Dm;+n/.HtJ#-[Ju{ceyHgaLlWMyα֓O6CoaI4}/Ohz*/cƀ&flŌo'QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5_Ot]Vs;| >UH O W'? Q'mϏuѣaMn^BtEF=t1kFF8+ĭUtז=2gNpwni1X ',DͥŬ%A9 s+]^iu{q @gs Pkcp!N?Ƭ+u3ڬ3wc\l;`0f;hT $,I,}$kK=L/ x#4 w>q| 7ֹ-BR=+ s!RTbN K]{K='YbIPC)^{%LvkW"ʙ8ڸ^8WVV;~qw_k[@Z]s]G=IFF]Bu+IRM#(cV8]u[OPӮce$CA r~(:w[AbUIR :&֫]iUVIq|g{JK/UV|J}x8ԦwkwV%F}mTWhNȶrzit7-`UKdn+iWjW^2EEtmcٱWAQ, }KbnXmZ?~vf"DRq$'MOU-#0]nnH Tv:y,>s d_͕p r=9,imwT%>Vm= j I%̌ q^o꺇,g[M@ᙣx䎵/ïؔy(_sV( OxzOд,+H9P0ߍh vG 1(HE `ڟEW7;W^B6KeqI>5FOj@֢(Z>Xt#m'W ]s]G=VY3Ͻ%2Ga ;Qv@jNDjehrsuhz|zu֕a=xo%4kR0*Ej߇ 9${Z^hEwXYǍۣF#&}WFs<E#:UEj߇ jNBqh|Dycs OR9gcth}0[oop8*=) I(w3"dl oڢE+VEKO6&o/Zvm\i>g3 F dǵYT_ݟ?Q?u&lF+'T_ݟ?Q?4'T_ݟ?Q? >g}/~(z*Ej߇ QvGڢ€'T_ݟ?Q? >g}/~(z*Ej߇ QvGڢ€'T_ݟ?Q? >g}/~(z*Ej߇ QvGڢ€'T_ݟ?Q? >g}/~(z*Ej߇ QvGڢ€'T_ݟ?Q? >g}/~(z*Ej߇ (((((((((((((((((((((((((((((((((((((((Ki^$eBcbc[8J/|[w<-v]H<@9KT}n#n8lEs o kMۻ?jO?|9L~odtŶy^M6pXmliCJ\ J+? DޛX\1Mw G͛vnsk^v6 mO2I#Er$YFGU5cZNw~Ԟ~1y݌sқ ?o\hyӞԢ($K&H-@OQ;uoe~[!{o/[ ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[n=UzV_6W ;uoe~[khH؅H$SYEp( ( ( ( ( ( ( ( ( +;.xKY}3OHhȎFV7.@]ut:WudHԢdf" :,ȷ?l0f` CvoMJ# eZȳyl0~s^E(T_K[цixFMVNkwkq|)B :e;q_[G΃xOC"GO/v,3*յ%uct ɫE/~DuYAn~`-<O6 tMRH<]6 [xO|5)3Rcq }E({V-K_ZQ@&pBI/m\%УtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEUMgAV꦳ tQEQEQEQEQEQEQEQEQEQEQEQEQEQETB_ :EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEUMgAEn((django-crispy-forms-1.4.0/docs/index.rst000066400000000000000000000035111221066745500202120ustar00rootroot00000000000000.. django-crispy-forms documentation master file, created by sphinx-quickstart on Tue Nov 1 19:01:02 2011. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Forms have never been this crispy ================================= django-crispy-forms provides you with a ``|crispy`` filter and ``{% crispy %}`` tag that will let you control the rendering behavior of your Django_ forms in a very elegant and DRY way. Have full control without writing custom form templates. All this without breaking the standard way of doing things in Django_, so it plays nice with any other form application. User Guide ~~~~~~~~~~ Get the most out of django-crispy-forms .. toctree:: :maxdepth: 2 install filters crispy_tag_forms form_helper layouts crispy_tag_formsets dynamic_layouts .. toctree:: :maxdepth: 1 faq * See who's contributed to the project at `crispy-forms contributors`_ * You can find a detailed history of the project in `Github's CHANGELOG`_ .. _`crispy-forms contributors`: https://github.com/maraujop/django-crispy-forms/blob/dev/CONTRIBUTORS.txt .. _`Github's CHANGELOG`: https://github.com/maraujop/django-crispy-forms/blob/dev/CHANGELOG.md API documentation ~~~~~~~~~~~~~~~~~ If you are looking for information on a specific function, class or method, this part of the documentation is for you. .. toctree:: :maxdepth: 2 api_helpers api_layout api_templatetags Developer Guide ~~~~~~~~~~~~~~~ Think this is awesome and want to make it better? Read our contribution page, make it better, and you will be added to the `contributors`_ list! .. toctree:: :maxdepth: 2 contributing .. _contributors: https://github.com/maraujop/django-crispy-forms/blob/dev/CONTRIBUTORS.txt .. _Django: http://djangoproject.com django-crispy-forms-1.4.0/docs/install.rst000066400000000000000000000144211221066745500205530ustar00rootroot00000000000000============ Installation ============ .. _`install`: Installing django-crispy-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Install latest stable version into your python path using pip or easy_install:: pip install --upgrade django-crispy-forms If you want to install development version (unstable), you can do so doing:: pip install git+git://github.com/maraujop/django-crispy-forms.git@dev#egg=django-crispy-forms Or, if you'd like to install the development version as a git repository (so you can ``git pull`` updates, use the ``-e`` flag with ``pip install``, like so:: pip install -e git+git://github.com/maraujop/django-crispy-forms.git@dev#egg=django-crispy-forms Add ``crispy_forms`` to your ``INSTALLED_APPS`` in settings.py:: INSTALLED_APPS = ( ... 'crispy_forms', ) In production environments, always activate Django template cache loader. This is available since Django 1.2 and what it does is basically load templates once, then cache the result for every subsequent render. This leads to a significant performance improvement. See how to set it up using fabulous `Django docs page`_. .. _`Django docs page`: https://docs.djangoproject.com/en/1.5/ref/templates/api/#django.template.loaders.cached.Loader Template packs ~~~~~~~~~~~~~~ Since version 1.1.0 of django-crispy-forms has built-in support for different CSS frameworks, known as template packs within django-crispy-forms: * ``bootstrap`` `Bootstrap`_ is crispy-forms's default template pack, version 2 of the popular simple and flexible HTML, CSS, and Javascript for user interfaces from Twitter. * ``bootstrap3`` Twitter Bootstrap version 3. * ``uni-form`` `Uni-form`_ is a nice looking, well structured, highly customizable, accessible and usable forms. * ``foundation`` `Foundation`_ In creators words "The most advanced responsive front-end framework in the world". This template pack is externally available through `crispy-forms-foundation`_ If your form CSS framework is not supported and it's open source, you can create a template pack for it and submit a pull request in Github or create a ``crispy-forms-templatePackName`` project and let me know, so I can link it. You can set your default template pack for your project using ``CRISPY_TEMPLATE_PACK`` Django settings variable, setting it to one of the previous keywords:: CRISPY_TEMPLATE_PACK = 'uni_form' .. _`Bootstrap`: http://twitter.github.com/bootstrap/index.html .. _`Foundation`: http://foundation.zurb.com/ .. _`crispy-forms-foundation`: https://github.com/sveetch/crispy-forms-foundation Setting media files ~~~~~~~~~~~~~~~~~~~ crispy-forms no longer includes static files. You will need to include yourself the proper corresponding media files, depending on what CSS framework (Template pack) you are using. This might involve one or more CSS and JS files. Read CSS framework's docs for help on how to set it up. Moving from django-uni-form to django-crispy-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ django-crispy-forms was started as a friendly fork of django-uni-form. We are aware that a name change implies some hassle updating imports and templates, here is some help mitigating it. This is what you should replace when upgrading: 1. Your ``ÌNSTALLED_APPS`` should point to ``crispy_forms`` instead of ``uni_form`` 2. All imports have to be done from crispy forms:: from uni_form.helper import FormHelper from crispy_forms.helper import FormHelper In Linux You can use `rpl`_ to easily find and update the proper lines. Run in the root of your project the following command. It is strongly recommended that you have your project in a VCS or a backup, so you can rollback if something goes wrong:: rpl -R uni_form. crispy_forms. . .. _`rpl`: http://www.laffeycomputer.com/rpl.html 3. All tags loading needs to be updated:: {% load uni_form_tags %} {% load crispy_forms_tags %} Using rpl:: rpl -R "{% load uni_form_tags %}" "{% load crispy_forms_tags %}" . 4. Until version 1.2.0 former tags and filters names worked without changing them, current versions will force updating your filters and tags:: |as_uni_form -----> |crispy {% uni_form %} ---> {% crispy %} |as_uni_errors ---> |as_crispy_errors |as_uni_field ----> |as_crispy_field Using rpl:: rpl -R "|as_uni_form" "|crispy" . rpl -R "{% uni_form" "{% crispy" . rpl -R "|as_uni_errors" "|as_crispy_errors" . rpl -R "|as_uni_field" "|as_crispy_field" . There is one filter that has been turned into a tag for extra layout power, so former filter name will not work. You will only need to update this if you have custom or overriden templates in your project:: field|with_class ------> {% crispy_field field %} 5. If you have ``UNIFORM_FAIL_SILENTLY`` setting variable defined, you have to rename it to ``CRISPY_FAIL_SILENTLY``. 6. crispy-forms renders your layouts strictly, exactly the fields mentioned, if you want crispy-forms to work the same way as django-uni-form you can set new ``FormHelper`` attribute ``render_unmentioned_fields`` to ``True``. Uni-form static files ~~~~~~~~~~~~~~~~~~~~~ `Uni-form`_ files are composed of two CSS files and one JS library based on jQuery. Uni-form's JS library provides some nice interactions, but you will need to link a copy of jQuery. Preferably you should use a `version hosted`_ on Google's CDN servers since the user's browser might already have it cached. .. _`version hosted`: http://scriptsrc.net/. For linking `Uni-form`_ static files add the proper lines to your HTML head. This is an example on how to do it if you are using ``STATIC_URL``:: Activate uni-form.jquery ~~~~~~~~~~~~~~~~~~~~~~~~ If you link `Uni-form`_ JS library do not forget to activate given forms:: .. _Django: http://djangoproject.com .. _`Uni-form`: http://sprawsm.com/uni-form django-crispy-forms-1.4.0/docs/layouts.rst000066400000000000000000000433141221066745500206100ustar00rootroot00000000000000.. `layouts`: ======= Layouts ======= Fundamentals ~~~~~~~~~~~~ Django-crispy-forms defines another powerful class called ``Layout``, which allows you to change the way the form fields are rendered. This allows you to set the order of the fields, wrap them in divs or other structures, add html, set ids, classes or attributes to whatever you want, etc. And all that without writing a custom form template, using programmatic layouts. Just attach the layout to a helper, layouts are optional, but probably the most powerful thing django-crispy-forms has to offer. A ``Layout`` is constructed by layout objects, which can be thought of as form components. All these components are explained later in :ref:`layout objects`, what you need to know now about them is that every component renders a different template and has a different purpose. Let’s write a couple of different layouts for our form, continuing with our form class example (note that the full form is not shown again). Some layout objects are specific to a template pack. For example ``ButtonHolder`` is for ``uni_form`` template_pack, while ``FormActions`` is for ``bootstrap`` template pack. Let's add a layout to our helper:: from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Fieldset, ButtonHolder, Submit class ExampleForm(forms.Form): [...] def __init__(self, *args, **kwargs): super(ExampleForm, self).__init__(*args, **kwargs) self.helper = FormHelper() self.helper.layout = Layout( Fieldset( 'first arg is the legend of the fieldset', 'like_website', 'favorite_number', 'favorite_color', 'favorite_food', 'notes' ), ButtonHolder( Submit('submit', 'Submit', css_class='button white') ) ) When we render the form now using:: {% load crispy_forms_tags %} {% crispy example_form %} We will get the fields wrapped in a fieldset, whose legend will be set to 'first arg is the legend of the fieldset'. The fields' order will be: ``like_website``, ``favorite_number``, ``favorite_color``, ``favorite_food`` and ``notes``. We also get a submit button wrapped in a ``
    `` which uni-form CSS positions in a nice way. That button has its CSS class set to ``button white``. This is just the tip of the iceberg: now imagine you want to add an explanation for what notes are, you can use ``HTML`` layout object:: Layout( Fieldset( 'Tell us your favorite stuff {{ username }}', 'like_website', 'favorite_number', 'favorite_color', 'favorite_food', HTML("""

    We use notes to get better, please help us {{ username }}

    """), 'notes' ) ) As you'll notice the fieldset legend is context aware and you can write it as if it were a chunk of a template where the form will be rendered. The ``HTML`` object will add a message before the notes input and it's also context aware. Note how you can wrap layout objects into other layout objects. Layout objects ``Fieldset``, ``Div``, ``MultiField`` and ``ButtonHolder`` can hold other Layout objects within. Let's do an alternative layout for the same form:: Layout( MultiField( 'Tell us your favorite stuff {{ username }}', Div( 'like_website', 'favorite_number', css_id = 'special-fields' ), 'favorite_color', 'favorite_food', 'notes' ) ) This time we are using a ``MultiField``, which is a layout object that as a general rule can be used in the same places as ``Fieldset``. The main difference is that this renders all the fields wrapped in a div and when there are errors in the form submission, they are shown in a list instead of each one surrounding the field. Sometimes the best way to see what layout objects do, is just try them and play with them a little bit. Layout objects attributes ~~~~~~~~~~~~~~~~~~~~~~~~~ All layout objects you can set kwargs that will be used as HTML attributes. For example if you want to turn autocomplete off for a field you can do:: Field('field_name', autocomplete='off') If you want to set html attributes, with words separated by hyphens like ``data-name``, as Python doesn't support hyphens in keyword arguments and hyphens are the usual notation in HTML, underscores will be translated into hyphens, so you would do:: Field('field_name', data_name="whatever") As ``class`` is a reserved keyword in Python, for it you will have to use ``css_class``. For example:: Field('field_name', css_class="black-fields") And id attribute is set using ``css_id``:: Field('field_name', css_id="custom_field_id") .. _`layout objects`: Universal layout objects ~~~~~~~~~~~~~~~~~~~~~~~~ These ones live in module ``crispy_forms.layout``. These are layout objects that are not specific to a template pack. We'll go one by one, showing usage examples: - **Div**: It wraps fields in a ``
    ``:: Div('form_field_1', 'form_field_2', 'form_field_3', ...) **NOTE** Mainly in all layout objects you can set kwargs that will be used as HTML attributes. As ``class`` is a reserved keyword in Python, for it you will have to use ``css_class``. For example:: Div('form_field_1', style="background: white;", title="Explication title", css_class="bigdivs") - **HTML**: A very powerful layout object. Use it to render pure html code. In fact it behaves as a Django template and it has access to the whole context of the page where the form is being rendered. This layout object doesn't accept any extra parameters than the html to render, you cannot set html attributes like in ``Div``:: HTML("{% if success %}

    Operation was successful

    {% endif %}") .. warning :: Beware that this is rendered in a standalone template, so if you are using custom templatetags or filters, don't forget to add your ``{% load custom_tags %}`` - **Field**: Extremely useful layout object. You can use it to set attributes in a field or render a specific field with a custom template. This way you avoid having to explicitly override the field's widget and pass an ugly ``attrs`` dictionary:: Field('password', id="password-field", css_class="passwordfields", title="Explanation") Field('slider', template="custom-slider.html") This layout object can be used to easily extend Django's widgets. If you want to render a Django form field as hidden you can simply do:: Field('field_name', type="hidden") If you need HTML5 attributes, you can easily do those using underscores ``data_name`` kwarg here will become into ``data-name`` in your generated html:: Field('field_name', data_name="special") Fields in bootstrap are wrapped in a ``
    ``. You may want to set extra classes in this div, for that do:: Field('field_name', wrapper_class="extra-class") - **Submit**: Used to create a submit button. First parameter is the ``name`` attribute of the button, second parameter is the ``value`` attribute:: Submit('search', 'SEARCH') Submit('search', 'SEARCH') Renders to:: - **Hidden**: Used to create a hidden input:: Hidden('name', 'value') - **Button**: Creates a button:: Button('name', 'value') - **Reset**: Used to create a reset input:: reset = Reset('name', 'value') - **Fieldset**: It wraps fields in a ``
    ``. The first parameter is the text for the fieldset legend, as we've said it behaves like a Django template:: Fieldset("Text for the legend {{ username }}", 'form_field_1', 'form_field_2' ) Uni-form layout objects ~~~~~~~~~~~~~~~~~~~~~~~ These ones live in module ``crispy_forms.layout``. Probably in the future they will be moved out to a ``uni_form`` module: - **ButtonHolder**: It wraps fields in a ``
    ``, which uni-form positions in a nice way. This is where form's submit buttons go in uni-form:: ButtonHolder( HTML(""), Submit('save', 'Save') ) - **MultiField**: It wraps fields in a ``
    `` with a label on top. When there are errors in the form submission it renders them in a list instead of each one surrounding the field:: MultiField("Text for the label {{ username }}", 'form_field_1', 'form_field_2' ) Bootstrap Layout objects ~~~~~~~~~~~~~~~~~~~~~~~~ These ones live under module ``crispy_forms.bootstrap``. - **FormActions**: It wraps fields in a ``
    ``. It is usually used to wrap form's buttons:: FormActions( Submit('save', 'Save changes'), Button('cancel', 'Cancel') ) .. image:: images/form_actions.png :align: center - **AppendedText**: It renders a bootstrap appended text input. The first parameter is the name of the field to add appended text to, then the appended text which can be HTML like. There is an optional parameter ``active``, by default set to ``False``, that you can set to a boolean to render appended text active:: AppendedText('field_name', 'appended text to show') AppendedText('field_name', '$', active=True) .. image:: images/appended_text.png :align: center - **PrependedText**: It renders a bootstrap prepended text input. The first parameter is the name of the field to add prepended text to, then the prepended text which can be HTML like. There is an optional parameter ``active``, by default set to ``False``, that you can set to a boolean to render prepended text active:: PrependedText('field_name', 'Prepended text to show') PrependedText('field_name', '@', placeholder="username") .. image:: images/prepended_text.png :align: center - **PrependedAppendedText**: It renders a combined prepended and appended text. The first parameter is the name of the field, then the prepended text and finally the appended text:: PrependedAppendedText('field_name', '$', '.00'), .. image:: images/appended_prepended_text.png :align: center - **InlineCheckboxes**: It renders a Django ``forms.MultipleChoiceField`` field using inline checkboxes:: InlineCheckboxes('field_name') .. image:: images/inline_checkboxes.png :align: center - **InlineRadios**: It renders a Django ``forms.ChoiceField`` field with its widget set to ``forms.RadioSelect`` using inline radio buttons:: InlineRadios('field_name') .. image:: images/inline_radios.jpg :align: center - **StrictButton**: It renders a button using ``