Quickstart
blog/forms.py
Create a file called forms.py
in the blog app directory and add these lines to it:
from django.forms import ModelForm
from .models import Post
class PostForm(ModelForm):
class Meta:
model = Post
fields = ['title']
class PostDeleteForm(ModelForm):
class Meta:
model = Post
fields = []
mysite/urls.py
Edit the main urls.py
file and add these lines to it:
from django.contrib import admin
from django.urls import path
from blog.views import post_create, post_edit, post_delete
urlpatterns = [
path('blog/create/', post_create, name='post_create'),
path('blog/edit/<int:pk>/', post_edit, name='post_edit'),
path('blog/delete/<int:pk>/', post_delete, name='post_delete'),
path('admin/', admin.site.urls),
]
blog/views.py
Edit the views.py
file and add these function to it:
from django.shortcuts import get_object_or_404, redirect, render
from .forms import PostForm, PostDeleteForm
from blog.models import Post
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect('post_create')
else:
form = PostForm()
return render(request,
'blog/post_create.html',
{
'form': form
})
def post_edit(request, pk=None):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST,
instance=post)
if form.is_valid():
form.save()
return redirect('post_create')
else:
form = PostForm(instance=post)
return render(request,
'blog/post_edit.html',
{
'form': form,
'post': post
})
def post_delete(request, pk=None):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostDeleteForm(request.POST,
instance=post)
if form.is_valid():
post.delete()
return redirect('post_create')
else:
form = PostDeleteForm(instance=post)
return render(request, 'blog/post_delete.html',
{
'form': form,
'post': post,
})
Templates
Add these files in the blog/templates/blog
directory:
post_create.html
<h1>Add new post</h1>
<form action="{% url 'post_create' %}"
method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="button" type="submit">Create</button>
</form>
post_edit.html
<h1>Edit post</h1>
<form action="{% url 'post_edit' post.pk %}"
method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="button" type="submit">Update</button>
</form>
post_delete.html
<h1>Delete post</h1>
<form action="{% url 'post_delete' post.pk %}" method="post">
{% csrf_token %}
{{ form }}
Are you sure you want to delete the following post?<br><br>
{{ post.title }}<br><br>
<button class="button" type="submit">Delete</button>
<a href="{% url 'post_create' %}">Cancel</a>
</form>
Full Tutorial
This tutorial shows how to use function-based views to create, edit and delete objects.
Setup
Run these commands to setup a project:
mkdir mysite && cd mysite
python3 -m venv venv
source venv/bin/activate
pip install django
django-admin startproject mysite .
python manage.py startapp blog
Edit the project settings.py
file and add the blog app configuration class to the INSTALLED_APPS
list:
INSTALLED_APPS = [
# HERE
'blog.apps.BlogConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Add a class called Post
to the blog app models.py
file:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=255,
unique=True)
Run migrations:
python manage.py makemigrations && \
python manage.py migrate
Create form
Create a file called forms.py
in the blog app directory and add these lines to it:
from django.forms import ModelForm
from .models import Post
class PostForm(ModelForm):
class Meta:
model = Post
fields = ['title']
ModelForm
is a helper class that allows us to create forms using existing models.- Use the
fields
attribute to define what fields the form should have.
Edit the main urls.py
file and add these lines to it:
from django.contrib import admin
from django.urls import path
# HERE
from blog.views import post_create
urlpatterns = [
# HERE
path('blog/create/',
post_create,
name='post_create'),
path('admin/', admin.site.urls),
]
Edit the blog app views.py
file and add a function called post_create
to it:
from django.shortcuts import render, redirect
from .forms import PostForm
from blog.models import Post
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect('post_create')
else:
form = PostForm()
return render(request,
'blog/post_create.html',
{
'form': form
})
- The
if request.method == 'POST':
line checks if a form has been posted using thePOST
method. - The
form
object is created from the request data using thePostForm
class we created earlier. - If the form validation succeeds, we save the object to the database using
form.save()
. - The
else
clause is executed when we visit theblog/create/
URL without posting the form. We need to create theform
object even if we are not posting any data so that the empty HTML form can be rendered on the page. - The
form
object is passed to the template in therender()
function context. A context is a dictionary that maps template variable names to Python objects.
Create a file called post_create.html
in the blog/templates/blog
directory and add these lines to it:
<h1>Add new post</h1>
<form action="{% url 'post_create' %}"
method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="button" type="submit">Create</button>
</form>
- The
csrf_token
provides protection against Cross Site Request Forgeries. - {{ form.as_p }} renders the form fields using
<p>
tags.
Visit /blog/create/
to create items:
Edit form
Edit the project urls.py
file and add the following path to it:
# HERE
from blog.views import post_create, post_edit
urlpatterns = [
path('blog/create/',
post_create,
name='post_create'),
# HERE
path('blog/edit/<int:pk>/',
post_edit,
name='post_edit'),
path('admin/', admin.site.urls),
]
Edit the blog app views.py
file and add a function called post_edit
to it:
from django.shortcuts import render, redirect, get_object_or_404
def post_edit(request, pk=None):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST,
instance=post)
if form.is_valid():
form.save()
return redirect('post_create')
else:
form = PostForm(instance=post)
return render(request,
'blog/post_edit.html',
{
'form': form,
'post': post
})
- The
get_objects_or_404()
function is used to find the blog post we want to edit using its primary key. It returns 404 Not Found error if the object doesn't exist. - We pass in the post object to the
PostForm
class using theinstance=post
parameter. This makes theform.save()
method update the object. Without it the method would create a new object, as happens with thepost_create
view. - The
instance=post
in theelse
clause populates the HTML form with the object data when we visit the page without sending aPOST
request.
Create a file called post_edit.html
in the blog/templates/blog
directory and add these lines to it:
<h1>Edit post</h1>
<form action="{% url 'post_edit' post.pk %}"
method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="button" type="submit">Update</button>
</form>
Visit /blog/edit/<id>/
to edit an item:
Delete form
Edit the blog/forms.py
file and add a class called PostDeleteForm
to it:
from django.forms import ModelForm
from .models import Post
class PostForm(ModelForm):
class Meta:
model = Post
fields = ['title']
# START
class PostDeleteForm(ModelForm):
class Meta:
model = Post
fields = []
# END
Edit the urls.py
file and add the following path to it:
from django.contrib import admin
from django.urls import path
# HERE
from blog.views import post_create, post_edit, post_delete
urlpatterns = [
path('blog/create/',
post_create,
name='post_create'),
path('blog/edit/<int:pk>/',
post_edit,
name='post_edit'),
# HERE
path('blog/delete/<int:pk>/',
post_delete,
name='post_delete'),
path('admin/', admin.site.urls),
]
Edit the blog app views.py
file and add a function called post_delete
to it:
from .forms import PostForm, PostDeleteForm
def post_delete(request, pk=None):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostDeleteForm(request.POST,
instance=post)
if form.is_valid():
post.delete()
return redirect('post_create')
else:
form = PostDeleteForm(instance=post)
return render(request, 'blog/post_delete.html',
{
'form': form,
'post': post,
})
- The
post_delete
view is very similar to thepost_edit
view but instead of updating the blog post, we delete it usingpost.delete()
.
Create a file called post_delete.html
in the blog/templates/blog
directory and add these lines to it:
<h1>Delete post</h1>
<form action="{% url 'post_delete' post.pk %}" method="post">
{% csrf_token %}
{{ form }}
Are you sure you want to delete the following post?:<br><br>
{{ post.title }}?<br><br>
<button class="button" type="submit">Delete</button>
<a href="{% url 'post_create' %}">Cancel</a>
</form>
Visit blog/delete/<id>/
to delete an item: