Building your first CRUD application with Django

Written by Fabien Schlegel

Fabien Schlegel

5 min

published: 1/14/2026

Building your first CRUD application with Django

You have explored models, views, and templates. It’s time to put it all together to build something concrete! This tutorial will guide you, step by step, in creating your first complete web application with Django.

We are going to build a mini note management system, a simple CRUD application.

What does CRUD mean?

CRUD is an acronym that designates the four basic operations for data management:

  • Create: Create new data.
  • Read: Read (display) existing data.
  • Update: Update existing data.
  • Delete: Delete existing data.

Mastering CRUD means mastering the foundation of most dynamic web applications.

To follow this guide, you must have Python and Django installed and a basic understanding of models, views, and templates.

Step 1: project and application creation

Open your terminal and let’s create the basic structure.

  1. Create the Django project:

    django-admin startproject mynotesproject
    cd mynotesproject
  2. Create the “notes” application:

    python manage.py startapp notes
  3. Register the application: Open mynotesproject/settings.py and add 'notes' to your INSTALLED_APPS list:

    # mynotesproject/settings.py
    INSTALLED_APPS = [
        # ... other apps
        'notes.apps.NotesConfig',
    ]

Step 2: The data model

Let’s define the structure of our notes.

In notes/models.py, create the Note model:

# notes/models.py
from django.db import models
from django.urls import reverse

class Note(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('note-detail', kwargs={'pk': self.pk})

The get_absolute_url method is a very useful Django convention. It returns the canonical URL for an object, which allows Django to know where to redirect the user after a creation or update operation.

Apply this model to the database:

python manage.py makemigrations
python manage.py migrate

Step 3: READ - displaying notes

Let’s start by displaying the existing notes.

The view (list and detail)

We will use generic Class-Based Views (CBV), as they are perfect for CRUD.

Modify notes/views.py:

# notes/views.py
from django.views.generic import ListView, DetailView
from .models import Note

class NoteListView(ListView):
    model = Note
    template_name = 'notes/note_list.html'
    context_object_name = 'notes'

class NoteDetailView(DetailView):
    model = Note
    template_name = 'notes/note_detail.html'
    context_object_name = 'note'

The templates (list and detail)

Create a templates/notes folder in your notes application.

notes/templates/notes/note_list.html

<h1>My Notes</h1>
<a href="{% url 'note-create' %}">Add a note</a>
<ul>
  {% for note in notes %}
  <li><a href="{{ note.get_absolute_url }}">{{ note.title }}</a></li>
  {% empty %}
  <li>No notes for now.</li>
  {% endfor %}
</ul>

notes/templates/notes/note_detail.html

<h1>{{ note.title }}</h1>
<p>{{ note.content|linebreaks }}</p>
<small>Created on: {{ note.created_at }}</small>
<hr />
<a href="{% url 'note-update' note.pk %}">Edit</a>
<a href="{% url 'note-delete' note.pk %}">Delete</a>
<a href="{% url 'note-list' %}">Back to list</a>

The |linebreaks filter transforms line breaks in the text into <p> and <br> tags.

The URLs

Create a notes/urls.py file:

# notes/urls.py
from django.urls import path
from .views import NoteListView, NoteDetailView

urlpatterns = [
    path('', NoteListView.as_view(), name='note-list'),
    path('note/<int:pk>/', NoteDetailView.as_view(), name='note-detail'),
]

Include these URLs in the main project mynotesproject/urls.py:

# mynotesproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('notes.urls')), # Include notes app URLs
]

Start the server (python manage.py runserver) and visit http://127.0.0.1:8000/. You should see your list of notes (empty for now).

Step 4: CREATE - creating a note with ModelForm

To create notes, we need forms. Django excels at this with ModelForm.

The form

Create a notes/forms.py file:

# notes/forms.py
from django import forms
from .models import Note

class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = ['title', 'content']

That’s it! Django will automatically generate a form based on the title and content fields of our Note model.

The view (CreateView)

Add CreateView to notes/views.py:

# notes/views.py
from django.views.generic import ListView, DetailView, CreateView
from .models import Note
from .forms import NoteForm

# ... NoteListView and NoteDetailView ...

class NoteCreateView(CreateView):
    model = Note
    form_class = NoteForm
    template_name = 'notes/note_form.html'
    # success_url will be handled by get_absolute_url on the model

The form template

Create notes/templates/notes/note_form.html. This template will serve for both creation and modification.

<h1>{% if object %}Edit Note{% else %}New Note{% endif %}</h1>
<form method="post">
  {% csrf_token %} {{ form.as_p }}
  <button type="submit">Save</button>
</form>
  • {% csrf_token %} is a mandatory security measure for POST forms.
  • {{ form.as_p }} displays each form field in a <p> paragraph.

The URL

Add the path in notes/urls.py:

# notes/urls.py
# ...
from .views import NoteListView, NoteDetailView, NoteCreateView

urlpatterns = [
    # ...
    path('note/new/', NoteCreateView.as_view(), name='note-create'),
]

You can now create notes!

Step 5: UPDATE - updating a note

The update view is very similar to the create view.

The view (UpdateView)

Add UpdateView to notes/views.py:

# notes/views.py
from django.views.generic import ListView, DetailView, CreateView, UpdateView
# ...

class NoteUpdateView(UpdateView):
    model = Note
    form_class = NoteForm
    template_name = 'notes/note_form.html'

We reuse the same note_form.html template.

The URL

Add the path in notes/urls.py:

# notes/urls.py
# ...
from .views import NoteListView, NoteDetailView, NoteCreateView, NoteUpdateView

urlpatterns = [
    # ...
    path('note/<int:pk>/edit/', NoteUpdateView.as_view(), name='note-update'),
]

Now, the “Edit” link on the detail page works.

Step 6: DELETE - deleting a note

The last operation of CRUD. Django asks for confirmation before deleting.

The view (DeleteView)

Add DeleteView to notes/views.py:

# notes/views.py
from django.urls import reverse_lazy
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
# ...

class NoteDeleteView(DeleteView):
    model = Note
    template_name = 'notes/note_confirm_delete.html'
    success_url = reverse_lazy('note-list')

reverse_lazy is used here because the URL is evaluated only at runtime, not when the file is loaded.

The confirmation template

Create notes/templates/notes/note_confirm_delete.html:

<h1>Delete Note</h1>
<p>Are you sure you want to delete the note: "{{ note.title }}"?</p>
<form method="post">
  {% csrf_token %}
  <button type="submit">Confirm deletion</button>
  <a href="{{ note.get_absolute_url }}">Cancel</a>
</form>

The URL

Add the path in notes/urls.py:

# notes/urls.py
# ...
from .views import (
    NoteListView,
    NoteDetailView,
    NoteCreateView,
    NoteUpdateView,
    NoteDeleteView
)

urlpatterns = [
    # ...
    path('note/<int:pk>/delete/', NoteDeleteView.as_view(), name='note-delete'),
]

Your CRUD application is complete!

Conclusion

Congratulations! You have just built a fully functional web application with Django, mastering the four CRUD operations. By using generic views (ListView, DetailView, CreateView, UpdateView, DeleteView) and ModelForm, you can build the foundation of any data management application with remarkable speed and efficiency.

Next steps could be:

  • Styling the templates with CSS.
  • Adding authentication so each user has their own notes.
  • Deploying your application to production.

Related Articles