# 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 }}