Giter VIP home page Giter VIP logo

django-form-utils's Introduction

django-form-utils

This application provides utilities for enhancing Django's form handling:

  1. BetterForm and BetterModelForm classes, which are subclasses of django.forms.Form and django.forms.ModelForm, respectively. BetterForm and BetterModelForm allow subdivision of forms into fieldsets which are iterable from a template, and also allow definition of row_attrs which can be accessed from the template to apply attributes to the surrounding container (<li>, <tr>, or whatever) of a specific form field.
  2. A variety of small template filters that are useful for giving template authors more control over custom rendering of forms without needing to edit Python code: label, value_text, selected_values, optional, is_checkbox, and is_multiple.
  3. A ClearableFileField to enhance FileField and ImageField with a checkbox for clearing the contents of the field.
  4. An ImageWidget which display a thumbnail of the image rather than just the filename.
  5. An AutoResizeTextarea widget which auto-resizes to accommodate its contents.

Installation

Install from PyPI with easy_install or pip:

pip install django-form-utils

To use django-form-utils in your Django project, just include form_utils in your INSTALLED_APPS setting. django-form-utils does not provide any models, but including it in INSTALLED_APPS makes the form_utils template tag library available.

You may also want to override the default form rendering templates by providing alternate templates at templates/form_utils/better_form.html and templates/form_utils/form.html.

Dependencies

django-form-utils is tested on Django 1.4 and later and Python 2.6, 2.7, and 3.3. It is known to be incompatible with Python 3.0, 3.1, and 3.2.

ImageWidget requires the Python Imaging Library. sorl-thumbnail or easy-thumbnails is optional, but without it full-size images will be displayed instead of thumbnails. The default thumbnail size is 200px x 200px.

AutoResizeTextarea requires jQuery (by default using a Google-served version; see JQUERY_URL).

Usage

BetterForm

Simply inherit your form class from form_utils.forms.BetterForm (rather than django.forms.Form), or your modelform class from form_utils.forms.BetterModelForm, and define the fieldsets and/or row_attrs attributes of the inner Meta class:

class MyForm(BetterForm):
    one = forms.CharField()
    two = forms.CharField()
    three = forms.CharField()
    class Meta:
        fieldsets = [('main', {'fields': ['two'], 'legend': ''}),
                     ('Advanced', {'fields': ['three', 'one'],
                                   'description': 'advanced stuff',
                                   'classes': ['advanced', 'collapse']})]
        row_attrs = {'one': {'style': 'display: none'}}

fieldsets

Fieldset definitions are similar to ModelAdmin fieldset definitions: each fieldset is a two-tuple with a name and an options dictionary. Valid fieldset options in the dictionary include:

fields

(required) A tuple of field names to display in this fieldset.

classes

A tuple/list of extra CSS classes to apply to the fieldset.

legend

This value, if present, will be the contents of a legend tag to open the fieldset. If not present the name of the fieldset will be used (so a value of '' for legend must be used if no legend is desired.)

description

A string of optional extra text to be displayed under the legend of the fieldset.

When iterated over, the fieldsets attribute of a BetterForm (or BetterModelForm) yields Fieldset s. Each Fieldset has a name attribute, a legend attribute, a classes attribute (the classes tuple collapsed into a space-separated string), and a description attribute, and when iterated over yields its BoundField s.

For backwards compatibility, a BetterForm or BetterModelForm can still be iterated over directly to yield all of its BoundField s, regardless of fieldsets.

If you set fieldsets on a BetterModelForm and don't set either the fields or exclude options on that form class, BetterModelForm will set fields to be the list of all fields present in your fieldsets definition. This avoids problems with forms that can't validate because not all fields are listed in a fieldset. If you manually set either fields or exclude, BetterModelForm assumes you know what you're doing and doesn't touch those definitions, even if they don't match the fields listed in your fieldsets.

For more detailed examples, see the tests in tests/tests.py.

row_attrs

The row_attrs declaration is a dictionary mapping field names to dictionaries of attribute/value pairs. The attribute/value dictionaries will be flattened into HTML-style attribute/values (i.e. {'style': 'display: none'} will become style="display: none"), and will be available as the row_attrs attribute of the BoundField.

A BetterForm or BetterModelForm will add a CSS class of "required" or "optional" automatically to the row_attrs of each BoundField depending on whether the field is required, and will also add a CSS class of "error" if the field has errors.

Rendering

A possible template for rendering a BetterForm:

{% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
{% for fieldset in form.fieldsets %}
  <fieldset class="{{ fieldset.classes }}">
  {% if fieldset.legend %}
    <legend>{{ fieldset.legend }}</legend>
  {% endif %}
  {% if fieldset.description %}
    <p class="description">{{ fieldset.description }}</p>
  {% endif %}
  <ul>
  {% for field in fieldset %}
    {% if field.is_hidden %}
      {{ field }}
    {% else %}
      <li{{ field.row_attrs }}>
        {{ field.errors }}
        {{ field.label_tag }}
        {{ field }}
      </li>
    {% endif %}
  {% endfor %}
  </ul>
  </fieldset>
{% endfor %}

One can also access the fieldset directly if any special casing needs to be done, e.g.:

{% for field in form.fieldsets.main %}
    ...
{% endfor %}

django-form-utils also provides a convenience template filter, render. It is used like this:

{% load form_utils %}

{{ form|render }}

By default, it will check whether the form is a BetterForm, and if so render it using the template form_utils/better_form.html. If not, it will render it using the template form_utils/form.html. (In either case, the form object will be passed to the render template's context as form).

The render filter also accepts an optional argument, which is a template name or comma-separated list of template names to use for rendering the form:

{{ form|render:"my_form_stuff/custom_form_template.html" }}

Utility Filters

All the below filters require {% load form_utils %} in the template where they are used.

These filters are complementary to the useful filters found in the django-widget-tweaks library for setting arbitrary attributes and classes on form field widgets; thus such filters are not provided in django-form-utils.

label

Render a label tag for the given form field by rendering the template forms/_label.html with the context field (the boundfield object), id (the form field id attribute), and label_text.

By default the Python-defined label text for the form field is used, but alternate label text can be provided as an argument to the filter:

{{ form.fieldname|label:"Alternate label" }}

value_text

Display the current value of the given form field in a human-readable way (i.e. display labels for choice values rather than the internal value). The current value may be the default value (for first-time rendering of a form) or the previously-input value (for repeat rendering of a form with errors). Usage:

{{ form.fieldname|value_text }}

selected_values

Similar to value_text, but for use with multiple-select form fields, and returns a list of selected values rather than a single string. Usage:

<ul>
  {% for selected_value in form.multiselect|selected_values %}
    <li>{{ selected_value }}</li>
  {% endfor %}
</ul>

optional

Return True if the given field is optional, False if it is required. Sample usage:

{% if form.fieldname|optional %}(optional){% endif %}

is_checkbox

Return True if the given field's widget is a CheckboxInput, False otherwise. Sample usage:

{% if form.fieldname|is_checkbox %}
  {{ form.fieldname }}
  {{ form.fieldname|label }}
{% else %}
  {{ form.fieldname|label }}
  {{ form.fieldname }}
{% endif %}

is_multiple

Return True if the given field is a MultipleChoiceField, False otherwise. Sample usage:

{% if form.fieldname|is_multiple %}
  {% for value in form.fieldname|selected_values %}{{ value }} {% endif %}
{% else %}
  {{ form.fieldname|value_text }}
{% endif %}

ClearableFileField

A replacement for django.forms.FileField that has a checkbox to clear the field of an existing file. Use as you would any other form field class:

from django import forms

from form_utils.fields import ClearableFileField

class MyModelForm(forms.ModelForm):
    pdf = ClearableFileField()

ClearableFileField also accepts two keyword arguments, file_field and template.

file_field is the instantiated field to actually use for representing the file portion. For instance, if you want to use ClearableFileField to replace an ImageField, and you want to use ImageWidget, you could do the following:

from django import forms

from form_utils.fields import ClearableFileField
from form_utils.widgets import ImageWidget

class MyModelForm(forms.ModelForm):
    avatar = ClearableFileField(
        file_field=forms.ImageField(widget=ImageWidget))

By default, file_field is a plain forms.FileField with the default forms.FileInput widget.

template is a string defining how the FileField (or alternative file_field) and the clear checkbox are displayed in relation to each other. The template string should contain variable interpolation markers %(input)s and %(checkbox)s. The default value is %(input)s Clear: %(checkbox)s.

To use ClearableFileField in the admin; just inherit your admin options class from form_utils.admin.ClearableFileFieldsAdmin instead of django.contrib.admin.ModelAdmin, and all FileFields and ImageFields in that model will automatically be made clearable (while still using the same file/image field/widget they would have otherwise, including any overrides you provide in formfield_overrides).

ClearableImageField

form_utils.fields.ClearableImageField is just a ClearableFileField with the default file field set to forms.ImageField rather than forms.FileField.

ImageWidget

A widget for representing an ImageField that includes a thumbnail of the current image in the field, not just the name of the file. (Thumbnails only available if sorl-thumbnail is installed; otherwise the full-size image is displayed). To use, just pass in as the widget class for an ImageField:

from django import forms

from form_utils.widgets import ImageWidget

class MyForm(forms.Form):
    pic = forms.ImageField(widget=ImageWidget())

ImageWidget accepts a keyword argument, template. This is a string defining how the image thumbnail and the file input widget are rendered relative to each other. The template string should contain variable interpolation markers %(input)s and %(image)s. The default value is %(input)s<br />%(image)s. For example, to display the image above the input rather than below:

pic = forms.ImageField(
    widget=ImageWidget(template='%(image)s<br />%(input)s'))

To use in the admin, set as the default widget for ImageField using formfield_overrides:

from django.db import models

from form_utils.widgets import ImageWidget

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = { models.ImageField: {'widget': ImageWidget}}

AutoResizeTextarea

Just import the widget and assign it to a form field:

from django import forms
from form_utils.widgets import AutoResizeTextarea

class MyForm(forms.Form):
    description = forms.CharField(widget=AutoResizeTextarea())

Or use it in formfield_overrides in your ModelAdmin subclass:

from django import forms
from django.contrib import admin
from form_utils.widgets import AutoResizeTextarea

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {forms.CharField: {'widget': AutoResizeTextarea()}}

There is also an InlineAutoResizeTextarea, which simply provides smaller default sizes suitable for use in a tabular inline.

Settings

JQUERY_URL

AutoResizeTextarea requires the jQuery Javascript library. By default, django-form-utils links to the most recent minor version of jQuery 1.8 available at ajax.googleapis.com (via the URL http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js). If you wish to use a different version of jQuery, or host it yourself, set the JQUERY_URL setting. For example:

JQUERY_URL = 'jquery.min.js'

This will use the jQuery available at STATIC_URL/jquery.min.js. Note that a relative JQUERY_URL is relative to STATIC_URL.

django-form-utils's People

Contributors

agriffis avatar bocribbz avatar carljm avatar chmodas avatar grunskis avatar jonklo avatar philippbosch avatar robhudson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-form-utils's Issues

RemovedInDjango19Warning

Since the release of Django 1.8 I'm getting this error:

... site-packages/form_utils/forms.py:12: RemovedInDjango19Warning: The django.forms.util module has been renamed. Use django.forms.utils instead.
from django.forms.util import flatatt, ErrorDict

[Question] Adding fields dynamically to a fieldset

Hello,

Iโ€™m trying to create a form with dynamically created fields, adding those fields to field sets depending on some conditions. By inspecting the library code I was trying like this:

class BuildCreateForm(BetterForm):
    description = forms.CharField(label = 'Description')

    def __init__(self, *args, **kwargs):
        product = kwargs.pop('product')

        super(BuildCreateForm, self).__init__(*args, **kwargs)

        for field in product.fields.all():
            field_id = 'field_%s' % field.pk
            self.fields[field_id] = forms.CharField(
                label = field.name,
                required = False)
            self.Meta.fieldsets[0][1]['fields'].append(field_id)

    class Meta:
        fieldsets = [('build_fields', {
            'fields': [],
            'legend': 'Fields'})]

which obviously fails, as adding something to Meta multiple times will be reflected in all instances (ie. refreshing my test page will display one more of the dynamic field after each refresh). As Fieldset has no method to add a field, I was wondering if it is actually possible.

Thanks in advance!

Best,
Gergely

RemovedInDjango110 warning: render() must be called with a dict, not a Context

/home/polesz/Projects/python/demand/venv/local/lib/python2.7/site-packages/form_utils/templatetags/form_utils.py:43: RemovedInDjango110Warning: render() must be called with a dict, not a Context.

This is an easy fix if you drop support for older (ie. unsupported) versions of Django; I made the change locally and it breaks everything up to and including 1.7.

form_util.forms.BetterModelForm and form_util.forms.BetterForm has a mixins

Hi,
Thanks for your great job !

I'm using autocomplete-light extension to django, but base forms provided with autocomplete and from form_utils are not compatibles : both of them inherit from "django.forms.(Model)Form"

I've posted the same issue on autocomplete-light github.

Thanks for your attention !

ImageWidget depends on having image decoder installed.

In the ImageWidget code, there is a line that checks whether value is an image:

if hasattr(value, 'width') and hasattr(value, 'height'):

This works great unless you don't have decoders that PIL needs for a specific file type.

For example:

If you store a JPEG image in your model but have no need to process it (no decoder or django-thumbnail-app is installed) then when that line runs PIL will throw and catch an IO error, causing the line to interpret as False This means it will render only the file upload input and not the image.

I find that to be unexpected behavior if I have no need for image processing.

Proposal: migrate project to Jazzband

Hi @carljm, I noticed you marked this project as unmaintained. Do you think there is still value in it? I thought we propose to transition it to the Jazzband to collectively maintain it.

I am mostly using the fieldset functionality, which works well for my use case (I pair it with a custom renderer for django-bootstrap3). I don't know whether the rest of the functionality is still relevant.

ImageWidget and Amazon S3

So, the two don't play together when you don't use utilize any thumbnail generator.
The reason is that instead of invoking the ImageField's url method, it performs a "manual" join between the project's media folder and the image path - and that simply doesn't work with remote storages such as Amazon's.

I have forked and fixed it for myself, and would like to send a pull request, but I have can't figure out how to run the tests - for some reason they are in the egg, but not in the app itself...

How do I run the tests?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.