Labs ICT
โญ Pro Login

ModelForms

Auto-generating forms from your models.

Introduction to ModelForms

ModelForms save you from writing repetitive form code. They automatically generate form fields from your model's fields.


from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content', 'published']
    

The Meta class tells Django which model to use and which fields to include in the form.

Customizing Widgets and Labels

You can customize how fields render by specifying widgets, labels, and help text.


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'content': forms.Textarea(attrs={'rows': 10}),
        }
        labels = {
            'title': 'Post Title',
        }
        help_text = {
            'content': 'Write your post content here.',
        }
    

Widgets control the HTML element used for each field. Labels and help text appear in the rendered form.

Saving Form Data

ModelForms have a convenient save() method that creates or updates model instances.


def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'post_form.html', {'form': form})
    

The save() method returns the new model instance. You can also call save(commit=False) to get an unsaved instance.

Using commit=False

Sometimes you need to set additional fields before saving. Use commit=False to get an unsaved instance.


def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'post_form.html', {'form': form})
    

This pattern is common when you need to set fields that aren't in the form, like the current user or a calculated value.

Try it Yourself โ†’

Overriding clean Methods

You can add custom validation by overriding clean_() or the clean() method.


class EventForm(forms.ModelForm):
    class Meta:
        model = Event
        fields = ['name', 'start_date', 'end_date']

    def clean(self):
        cleaned_data = super().clean()
        start = cleaned_data.get('start_date')
        end = cleaned_data.get('end_date')
        if start and end and start > end:
            raise forms.ValidationError('End date must be after start date.')
        return cleaned_data
    

The clean() method lets you validate relationships between multiple fields. Always call super().clean() first.

๐Ÿงช Quick Quiz

What does a ModelForm do?