Formsets and Inlines

PRO-only

Django formsets let you edit multiple related objects at once. Viewflow adds two field types that embed formsets inside a parent form, so you don’t need separate views for related data.

ModelFormField

Use ModelFormField for one-to-one relationships. It nests one form inside another.

from viewflow.forms import ModelFormField

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['bio', 'website']

class UserForm(forms.ModelForm):
    profile = ModelFormField(form_class=UserProfileForm)

    class Meta:
        model = User
        fields = ['username', 'email', 'profile']

This creates a single form where you edit the User and their UserProfile together.

InlineFormSetField

Use InlineFormSetField for one-to-many relationships. It embeds a formset that lets users add, edit, and delete multiple related objects.

from viewflow.forms import InlineFormSetField

OrderItemFormSet = inlineformset_factory(
    Order, OrderItem, fields=('product', 'quantity'), extra=1
)

class OrderForm(forms.ModelForm):
    items = InlineFormSetField(formset_class=OrderItemFormSet)

    class Meta:
        model = Order
        fields = ['customer', 'date']

This creates an Order form with a table of OrderItems. Users can add rows, edit existing ones, and delete items.

Many-to-Many Relationships

InlineFormSetField also works for many-to-many relationships. Use the through model.

from django.contrib.auth.models import User, Group
from django.forms.models import inlineformset_factory
from viewflow.forms import ModelForm, InlineFormSetField, AjaxModelSelect


GroupFormSet = inlineformset_factory(
    User,
    Group.user_set.through,
    fields=("group",),
    can_delete=False,
    extra=1,
    widgets={"group": AjaxModelSelect(lookups=["name__istartswith"])},
)


class UserForm(ModelForm):
    groups = InlineFormSetField(formset_class=GroupFormSet)

    class Meta:
        model = User
        fields = ["username", "first_name", "last_name"]

This adds a group selector to the User form. The AjaxModelSelect widget loads groups on demand instead of fetching all at once.