# Working with Forms Integrating `django_tomselect` into your forms is straightforward and leverages the familiar patterns of standard Django forms and ModelForms. Whether you’re working with simple stand-alone forms or complex model-backed forms with dynamic fields and validation, `django_tomselect` fits naturally into the Django form ecosystem. ## Basic Form Integration Building on the basic form from the [Quickstart](quickstart.md), you can drop `django_tomselect` fields into any regular Django form to add autocompletion, pagination, and other interactive features automatically. The sections below cover the patterns that go beyond that starter form. ## Working with ModelForms When dealing with database-backed models, `ModelForm` provides a more integrated solution. By using `TomSelectModelChoiceField` or `TomSelectModelMultipleChoiceField`, you can seamlessly integrate autocompletes into your forms: ```python from django import forms from django_tomselect import ( TomSelectConfig, TomSelectModelChoiceField, TomSelectModelMultipleChoiceField, ) from .models import Article class ArticleForm(forms.ModelForm): magazine = TomSelectModelChoiceField( config=TomSelectConfig( url="autocomplete-magazine", value_field="id", label_field="name", ) ) authors = TomSelectModelMultipleChoiceField( config=TomSelectConfig( url="autocomplete-author", value_field="id", label_field="name", placeholder="Select authors...", max_items=None, # Allow any number of authors ) ) class Meta: model = Article fields = ["title", "magazine", "authors"] ``` ModelForms automatically populate initial values from the provided model instance, and saving the form updates the related database records as normal. ## Handling Initial Values `django_tomselect` handles initial values just like any other Django form field. For ModelForms, the field will display the current related objects, so if you’re editing an existing `Article`: ```python from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse def article_edit_view(request, pk): article = get_object_or_404(Article, pk=pk) form = ArticleForm(request.POST or None, instance=article) if request.method == "POST" and form.is_valid(): form.save() return redirect("article-list") return TemplateResponse(request, "article_form.html", {"form": form}) ``` When loading this form, the `magazine` and `authors` fields will be pre-filled with the article’s current magazine and authors, allowing users to adjust the selection as needed. ## Dynamic Form Fields A powerful feature of `django_tomselect` is the ability to dynamically update form fields based on other fields’ values-also known as dependent or chained fields. For example, you might want the `edition` field to show only editions from the currently selected `magazine`. ```python class DynamicArticleForm(forms.ModelForm): magazine = TomSelectModelChoiceField( config=TomSelectConfig( url="autocomplete-magazine", value_field="id", label_field="name", ) ) edition = TomSelectModelChoiceField( config=TomSelectConfig( url="autocomplete-edition", value_field="id", label_field="name", filter_by=("magazine", "magazine_id"), # Filter editions by selected magazine ), required=False, ) class Meta: model = Article fields = ["title", "magazine", "edition"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Dynamically set the initial value for 'edition' if the instance already has a related edition if self.instance and self.instance.magazine and self.instance.edition: self.fields["edition"].initial = self.instance.edition.pk ``` In this scenario, when the `magazine` field changes, the widget triggers the `edition` field to refresh its options via AJAX, ensuring users see only editions relevant to the chosen magazine. ## Form Validation `django_tomselect` fields integrate with Django’s form validation system. You can write custom clean methods or field-specific validators just like any other form field. The following example ensures the selected `primary_author` is not also chosen as a contributing author: ```python class AuthorArticleForm(forms.ModelForm): primary_author = TomSelectModelChoiceField( config=TomSelectConfig( url="autocomplete-author", value_field="id", label_field="name", ) ) contributing_authors = TomSelectModelMultipleChoiceField( config=TomSelectConfig( url="autocomplete-author", value_field="id", label_field="name", exclude_by=("primary_author", "id"), ) ) class Meta: model = Article fields = ["title", "primary_author", "contributing_authors"] def clean(self): cleaned_data = super().clean() primary = cleaned_data.get("primary_author") contributors = cleaned_data.get("contributing_authors", []) if primary and primary in contributors: raise forms.ValidationError( "The primary author cannot also be a contributing author." ) return cleaned_data ``` ## Form Rendering Since `django_tomselect` fields are just Django form fields with a special widget, you can render them using all the standard approaches: ```html {{ form.as_p }}
{{ form.magazine }} {% if form.magazine.errors %}
{{ form.magazine.errors }}
{% endif %} {% if form.magazine.help_text %} {{ form.magazine.help_text }} {% endif %}
``` TomSelect’s JavaScript and CSS are automatically included based on your configuration. By combining this rendering flexibility with Django’s robust form ecosystem, you can easily integrate powerful autocomplete and selection features into even the most complex forms.