Django Tutorial
Django Create A Complete Project
Django Template
Django Database Query
Django Form
Django Authentication and Permission Management
Django unittest
Django Advanced
Django Define a Form Based on Model Tutorial
In this tutorial, we'll learn how to create a form based on a model in Django. Model forms make it easy to create forms that interact with your database models, streamlining form rendering, validation, and data processing.
Prerequisites:
Assuming we have an app named 'myapp' with the following models.py
:
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) email = models.EmailField() class Book(models.Model): title = models.CharField(max_length=100) author = models.ForeignKey(Author, on_delete=models.CASCADE) publication_date = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2)
Step 1: Create a model form
1.1. In your Django app, create a new file called forms.py
. Inside the file, import the necessary modules and create a form based on the Book
model:
from django import forms from .models import Book class BookForm(forms.ModelForm): class Meta: model = Book fields = ['title', 'author', 'publication_date', 'price']
The Meta
class inside the form specifies the model and the fields to be included in the form. You can customize the form further by adding additional fields, modifying form field attributes, and adding validation methods.
Step 2: Use the form in a view
2.1. In your app's views.py
, import the form and create a view to handle form rendering and submission:
from django.shortcuts import render, redirect from .models import Book from .forms import BookForm def create_book(request): if request.method == 'POST': form = BookForm(request.POST) if form.is_valid(): form.save() return redirect('myapp:book_list') else: form = BookForm() return render(request, 'myapp/create_book.html', {'form': form})
This view handles both GET and POST requests. When the user submits the form (POST request), the view validates the form data and saves it to the database if it's valid. If the form is not valid, it displays the form with error messages. When the user visits the page initially (GET request), the view renders an empty form.
Don't forget to replace 'myapp:book_list'
with the appropriate URL name for your app.
Step 3: Create a template to display the form
3.1. In your app's templates folder, create a new template called create_book.html
and use the following code to display the form:
{% extends "base.html" %} {% block content %} <h2>Create a new book</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Save</button> </form> {% endblock %}
This template extends a base template and renders the form inside a form element. The {{ form.as_p }}
tag renders the form as a series of paragraphs, with each field enclosed in a <p>
tag.
Step 4: Add URL pattern
4.1. In your app's urls.py
, add a new URL pattern for the create_book
view:
from django.urls import path from . import views app_name = 'myapp' urlpatterns = [ # Other URL patterns... path('create_book/', views.create_book, name='create_book'), ]
Here, we define a new URL pattern that maps to the create_book
view in our views.py
file. We assign a name 'create_book' to this URL pattern, which can be used for reverse URL resolution in templates and views.
Step 5: Include the app's URLs in the project URLs
5.1. In your project's urls.py
file, make sure you include your app's URLs:
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('myapp/', include('myapp.urls')), ]
Replace 'myapp/'
with the desired URL prefix for your app, and 'myapp.urls'
with the appropriate path to your app's urls.py
file.
Now, when you run your Django development server, you should be able to access the create_book
view by visiting the URL that corresponds to the URL pattern you defined, such as http://127.0.0.1:8000/myapp/create_book/
.
Creating forms from models in Django:
Description: Django allows you to create forms directly from models, simplifying the process of handling form data that corresponds to database models.
Code Example:
# models.py from django.db import models class MyModel(models.Model): name = models.CharField(max_length=100) email = models.EmailField()
# forms.py from django import forms from .models import MyModel class MyModelForm(forms.ModelForm): class Meta: model = MyModel fields = ['name', 'email']
Django model form example:
Description: A simple example demonstrating how to create a ModelForm for a Django model.
Code Example:
# models.py from django.db import models class Product(models.Model): name = models.CharField(max_length=100) price = models.DecimalField(max_digits=5, decimal_places=2)
# forms.py from django import forms from .models import Product class ProductForm(forms.ModelForm): class Meta: model = Product fields = ['name', 'price']
How to use ModelForm in Django:
# views.py from django.shortcuts import render from .forms import ProductForm def create_product(request): if request.method == 'POST': form = ProductForm(request.POST) if form.is_valid(): form.save() else: form = ProductForm() return render(request, 'create_product.html', {'form': form})
Django forms for model instances:
# views.py from django.shortcuts import render, get_object_or_404 from .forms import ProductForm from .models import Product def edit_product(request, product_id): product = get_object_or_404(Product, pk=product_id) if request.method == 'POST': form = ProductForm(request.POST, instance=product) if form.is_valid(): form.save() else: form = ProductForm(instance=product) return render(request, 'edit_product.html', {'form': form})
ModelForm vs. regular forms in Django:
# Regular form class MyForm(forms.Form): name = forms.CharField(max_length=100) email = forms.EmailField()
Django form fields for model fields:
# forms.py from django import forms from .models import MyModel class MyModelForm(forms.ModelForm): custom_field = forms.CharField() class Meta: model = MyModel fields = ['name', 'email']
Customizing Django ModelForm behavior:
clean
, save
, or defining custom validation logic.# forms.py from django import forms from .models import MyModel class MyModelForm(forms.ModelForm): class Meta: model = MyModel fields = ['name', 'email'] def clean_name(self): # Custom validation logic for the 'name' field name = self.cleaned_data['name'] if name.startswith('X'): raise forms.ValidationError("Name cannot start with 'X'") return name
Django ModelForm initial data:
# views.py from .forms import ProductForm from .models import Product def edit_product(request, product_id): product = get_object_or_404(Product, pk=product_id) if request.method == 'POST': form = ProductForm(request.POST, instance=product) if form.is_valid(): form.save() else: form = ProductForm(instance=product, initial={'name': 'Initial Name'}) return render(request, 'edit_product.html', {'form': form})
Django dynamic forms with ModelForm:
# forms.py from django import forms from .models import MyModel class MyDynamicForm(forms.ModelForm): class Meta: model = MyModel fields = ['name', 'email'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if some_condition: self.fields['additional_field'] = forms.CharField()
Django formsets with ModelForm:
# views.py from django.forms import modelformset_factory from .forms import ProductForm from .models import Product ProductFormSet = modelformset_factory(Product, form=ProductForm, extra=3) def manage_products(request): if request.method == 'POST': formset = ProductFormSet(request.POST, queryset=Product.objects.all()) if formset.is_valid(): formset.save() else: formset = ProductFormSet(queryset=Product.objects.all()) return render(request, 'manage_products.html', {'formset': formset})
Django form rendering for model forms:
{% for field in form %}
loop to display form fields.<!-- templates/manage_products.html --> <form method="post" action="{% url 'manage_products' %}"> {% csrf_token %} {{ formset.management_form }} {% for form in formset %} {{ form.as_p }} {% endfor %} <input type="submit" value="Submit"> </form>