Forms

class towel.forms.BatchForm(request, queryset, *args, **kwargs)

This form class can be used to provide batch editing functionality in list views, similar to Django’s admin actions.

You have to implement your batch processing in the _context() method. This method only receives one parameter, a queryset which is already filtered according to the selected items on the list view. Additionally, the current request is available as an attribute of the form instance, self.request.

The method process(self) may have the following return values:

  • A dict instance: Will be merged into the template context.
  • A HttpResponse instance: Will be returned directly to the client.
  • An iterable: The handler assumes successful processing of all objects contained in the iterable.
  • Nothing: Nothing happens.

Usage example:

class AddressBatchForm(BatchForm):
    subject = forms.CharField()
    body = forms.TextField()

    def process(self):
        # Form validation has already been taken care of
        subject = self.cleaned_data.get('subject')
        body = self.cleaned_data.get('body')

        if not (subject and body):
            return {}

        sent = 0
        for item in self.batch_queryset:
            send_mail(subject, body, settings.DEFAULT_SENDER,
                [item.email])
            sent += 1
        if sent:
            messages.success(self.request, 'Sent %s emails.' % sent)

        return self.batch_queryset

def addresses(request):
    queryset = Address.objects.all()
    batch_form = AddressBatchForm(request, queryset)
    ctx = {'addresses': queryset}

    if batch_form.should_process():
        result = form.process()
        if isinstance(result, HttpResponse):
            return result
        elif isinstance(result, dict):
            ctx.update(result)
        elif hasattr(result, '__iter__'):
            messages.success(request,
                _('Processed the following items: %s') % (
                    ', '.join(force_text(item) for item in result)))

        return HttpResponseRedirect('.')

    return render(request, 'addresses.html', ctx)

Template code:

{% load towel_batch_tags %}
<form method="post" action=".">
    <ul>
    {% for address in addresses %}
        <li>
        {% batch_checkbox address.id batch_form %}
        {{ address }}
        </li>
    {% endfor %}
    </ul>

    {# Required! Otherwise, ``BatchForm.process`` does nothing. #}
    <input type="hidden" name="batchform" value="1" />

    <table>
        {{ batch_form }}
    </table>
    <button type="submit">Send mail to selected</button>
</form>
batch_queryset

Returns the queryset containing only items that have been selected for batch processing.

clean()

Cleans the batch form fields and checks whether at least one item had been selected.

process()

Actually processes the batch form submission. Override this with your own behavior.

Batch forms may return the following types here (they are handled by ModelView.handle_batch_form:

  • A HttpResponse: Will be returned directly to the user.
  • An iterable: A success message will be generated containing all items in the iterable.
should_process()

Returns true when the submitted form was the batch form, and the batch form is valid.

class towel.forms.ModelAutocompleteWidget(attrs=None, url=None, queryset=None)

Model autocompletion widget using jQuery UI Autocomplete

Supports both querysets and JSON-returning AJAX handlers as data sources. Use as follows:

class MyForm(forms.ModelForm):
    customer = forms.ModelChoiceField(Customer.objects.all(),
        widget=ModelAutocompleteWidget(url='/customers/search_ajax/'),
        )
    type = forms.ModelChoiceField(Type.objects.all(),
        widget=ModelAutocompleteWidget(queryset=Type.objects.all()),
        )

You need to make sure that the jQuery UI files are loaded correctly yourself.

class towel.forms.MultipleAutocompletionWidget(attrs=None, queryset=None)

You should probably use harvest chosen instead.

class towel.forms.SearchForm(data, *args, **kwargs)

Supports persistence of searches (stores search in the session). Requires not only the GET parameters but the request object itself to work correctly.

Usage example:

class AddressManager(SearchManager):
    search_fields = ('first_name', 'last_name', 'address', 'email',
        'city', 'zip_code', 'created_by__email')

class Address(models.Model):
    ...

    objects = AddressManager()

class AddressSearchForm(SearchForm):
    orderings = {
        '': ('last_name', 'first_name'), # Default
        'dob': 'dob', # Sort by date of birth
        'random': lambda queryset: queryset.order_by('?'),
        }
    is_person = forms.NullBooleanField()

def addresses(request):
    search_form = AddressSearchForm(request.GET, request=request)
    queryset = search_form.queryset(Address)
    ctx = {
        'addresses': queryset,
        'search_form': search_form,
        }
    return render(request, 'addresses.html', ctx)

Warning

All fields in the form need to have required=False set. Otherwise, form validation would already fail on the first visit on the list page (which would kind of defeat the purpose of a search form).

Template code:

<form method="get" action=".">
    <input type="hidden" name="s" value="1"> <!-- SearchForm search -->
    <table>
        {{ search_form }}
    </table>
    <button type="submit">Search</button>
</form>

{% for address in addresses %}
    ...
{% endfor %}
always_exclude = (u's', u'query', u'o')

Fields which are always excluded from automatic filtering in apply_filters

apply_filters(queryset, data, exclude=())

Automatically apply filters

Uses form field names for filter() argument construction.

apply_ordering(queryset, ordering=None)

Applies ordering if the value in o matches a key in self.orderings. The ordering may also be reversed, in which case the o value should be prefixed with a minus sign.

default = {}

Default field values - used if not overridden by the user

fields_iterator()

Yield all additional search fields.

o = None

Current ordering

orderings = {}

Ordering specification

persist(request)

Persist the search in the session, or load saved search if user isn’t searching right now.

post_init(request)

Hook for customizations.

prepare_data(data, request)

Fill in default values from default if they aren’t provided by the user.

query = None

Full text search query

query_data()

Return a fulltext query and structured data which can be converted into simple filter() calls

queryset(model)

Return the result of the search

quick_rules = []

Quick rules, a list of (regex, mapper) tuples

s = None

Search form active?

safe_cleaned_data

Safely return a dictionary of values, even if search form isn’t valid.

searching()

Returns searching for use as CSS class if results are filtered by this search form in any way.

class towel.forms.StrippedTextInput(attrs=None)

TextInput form widget subclass returning stripped contents only

class towel.forms.StrippedTextarea(attrs=None)

Textarea form widget subclass returning stripped contents only

class towel.forms.WarningsForm(*args, **kwargs)

Form subclass which allows implementing validation warnings

In contrast to Django’s ValidationError, these warnings may be ignored by checking a checkbox.

The warnings support consists of the following methods and properties:

  • WarningsForm.add_warning(<warning>): Adds a new warning message
  • WarningsForm.warnings: A list of warnings or an empty list if there are none.
  • WarningsForm.is_valid(): Overridden Form.is_valid() implementation which returns False for otherwise valid forms with warnings, if those warnings have not been explicitly ignored (by checking a checkbox or by passing ignore_warnings=True to is_valid().
  • An additional form field named ignore_warnings is available - this field should only be displayed if WarningsForm.warnings is non-emtpy.
add_warning(warning)

Adds a new warning, should be called while cleaning the data

is_valid(ignore_warnings=False)

is_valid() override which returns False for forms with warnings if these warnings haven’t been explicitly ignored

towel.forms.autocompletion_response(queryset, limit=10)

Helper which returns a HttpResponse list of instances in a format suitable for consumption by jQuery UI Autocomplete, respectively towel.forms.ModelAutocompleteWidget.

towel.forms.towel_formfield_callback(field, **kwargs)

Use this callback as formfield_callback if you want to use stripped text inputs and textareas automatically without manually specifying the widgets. Adds a dateinput class to date and datetime fields too.