Form, fields and widgets

Note

This chapter assumes that you have been through Quick start: adding simple autocompletes and Autocomplete classes.

Design documentation

This app provides optionnal helpers to make forms:

You probably already know that Django has form-fields for validation and each form-field has a widget for rendering logic.

autocomplete_light.FieldBase makes a form field field rely on an Autocomplete class for initial choices and validation (hail DRY configuration !), it is used as a mixin to make some simple field classes:

In the very same fashion, autcomplete_light.WidgetBase renders a template which should contain:

  • a hidden <select> field containing real field values,
  • a visible <input> field which has the autocomplete,
  • a deck which contains the list of selected values,
  • add-another optionnal link, because add-another works outside the admin,
  • a hidden choice template, which is copied when a choice is created on the fly (ie. with add-another).

It is used as a mixin to make some simple widget classes:

Examples

This basic example demonstrates how to use an autocomplete form field in a form:

class YourForm(forms.Form):
    os = autocomplete_light.ChoiceField('OsAutocomplete')

Using autocomplete_light.ModelForm

Consider such a model which have every kind of relations that are supported out of the box:

class FullModel(models.Model):
    name = models.CharField(max_length=200)

    oto = models.OneToOneField('self', related_name='reverse_oto')
    fk = models.ForeignKey('self', related_name='reverse_fk')
    mtm = models.ManyToManyField('self', related_name='reverse_mtm')

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    gfk = generic.GenericForeignKey("content_type", "object_id")

    # that's generic many to many as per django-generic-m2m
    gmtm = RelatedObjectsDescriptor()

Assuming that you have registered an Autocomplete for FullModel and a generic Autocomplete, then autocomplete_light.ModelForm will contain 5 autocompletion fields by default: oto, fk, mtm, gfk and gmtm.

class FullModelModelForm(autocomplete_light.ModelForm):
    class Meta:
        model = FullModel
        # add for django 1.6:
        fields = '__all__'

autocomplete_light.ModelForm gives autocompletion super powers to django.forms.ModelForm. To disable the fk input for example:

class FullModelModelForm(autocomplete_light.ModelForm):
    class Meta:
        model = FullModel
        exclude = ['fk']

Or, to just get the default <select> widget for the fk field:

class FullModelModelForm(autocomplete_light.ModelForm):
    class Meta:
        model = FullModel
        autocomplete_exclude = ['fk']

In the same fashion, you can use Meta.fields and Meta.autocomplete_fields. To the difference that they all understand generic foreign key names and generic relation names in addition to regular model fields.

Not using autocomplete_light.ModelForm

Instead of using our autocomplete_light.ModelForm, you could create such a ModelForm using our mixins:

class YourModelForm(autocomplete_light.SelectMultipleHelpTextRemovalMixin,
        autocomplete_light.VirtualFieldHandlingMixin,
        autocomplete_light.GenericM2MRelatedObjectDescriptorHandlingMixin,
        forms.ModelForm):
    pass

This way, you get a fully working ModelForm which does not handle any field generation. You can use form fields directly though, which is demonstrated in the next example.

Using form fields directly

You might want to use form fields directly for any reason:

  • you don’t want to or can’t extend autocomplete_light.ModelForm,
  • you want to override a field, ie. if you have several Autocomplete classes registered for a model or for generic relations and you want to specify it,
  • you want to override any option like placeholder, help_text and so on.

Considering the model of the above example, this is how you could do it:

class FullModelModelForm(autocomplete_light.ModelForm):
    # Demonstrate how to use a form field directly
    oto = autocomplete_light.ModelChoiceField('FullModelAutocomplete')
    fk = autocomplete_light.ModelChoiceField('FullModelAutocomplete')
    m2m = autocomplete_light.ModelMultipleChoiceField('FullModelAutocomplete')
    # It will use the default generic Autocomplete class by default
    gfk = autocomplete_light.GenericModelChoiceField()
    gmtm = autocomplete_light.GenericModelMultipleChoiceField()

    class Meta:
        model = FullModel
        # django 1.6:
        fields = '__all__'

As you see, it’s as easy as 1-2-3, but keep in mind that this can break DRY: Model field’s help_text and verbose_name are lost when overriding the widget.

Using your own form in a ModelAdmin

You can use this form in the admin too, it can look like this:

from django.contrib import admin

from forms import OrderForm
from models import Order

class OrderAdmin(admin.ModelAdmin):
    form = OrderForm
admin.site.register(Order, OrderAdmin)

Note

Ok, this has nothing to do with django-autocomplete-light because it is plain Django, but still it might be useful to someone.