Django for Beginners: Building Your First Simple CRUD App

Welcome, aspiring web developers! If you’re looking to dive into the world of web development with a powerful and elegant framework, Django is an excellent choice. It’s built by experienced developers, takes care of a lot of the heavy lifting, and encourages good design practices.

In this beginner-friendly guide, we’ll walk through creating a simple “To-Do List” application using Django. This app will demonstrate the core principles of web development known as CRUD operations: Create, Read, Update, and Delete. By the end, you’ll have a foundational understanding of how Django works and how to build basic interactive web applications.

What is Django?

Django is a high-level Python web framework that enables rapid development of secure and maintainable websites. It follows the “Don’t Repeat Yourself” (DRY) principle, meaning you write less code, and it provides many features out-of-the-box, saving you time and effort. Think of it as a complete toolbox for building websites, offering tools for handling databases, URLs, user authentication, and much more.

What is CRUD?

CRUD is a fundamental concept in database-driven applications. It stands for:
* Create: Adding new data (e.g., adding a new To-Do item).
* Read: Viewing existing data (e.g., seeing your list of To-Do items).
* Update: Modifying existing data (e.g., changing a To-Do item’s description).
* Delete: Removing data (e.g., deleting a completed To-Do item).

Almost every web application you use today relies on these four basic operations.

Setting Up Your Environment

Before we start coding, let’s set up our development environment.

Prerequisites

You’ll need Python and pip (Python’s package installer) installed on your system. Most modern operating systems come with Python pre-installed. You can check by opening your terminal or command prompt and typing:

python --version
pip --version

If you don’t have them, please refer to the official Python website for installation instructions.

Virtual Environment Magic

It’s a best practice to use a virtual environment for every Django project.
* Supplementary Explanation: Virtual Environment
A virtual environment creates an isolated space for your project’s Python packages. This prevents conflicts between different projects that might require different versions of the same package. It keeps your project dependencies clean and manageable.

To create and activate a virtual environment:

  1. Navigate to where you want to store your project (e.g., Documents/DjangoProjects).
  2. Create a new directory for your project:
    bash
    mkdir mycrudproject
    cd mycrudproject
  3. Create the virtual environment (we’ll name it .venv):
    bash
    python -m venv .venv
  4. Activate the virtual environment:
    • On macOS/Linux:
      bash
      source .venv/bin/activate
    • On Windows:
      bash
      .\.venv\Scripts\activate

      You’ll know it’s active when you see (.venv) at the beginning of your terminal prompt.

Installing Django

Now that your virtual environment is active, install Django:

pip install django

Starting Your Django Project

Django projects are structured into a “project” and one or more “apps.” A project is the entire website, while an app is a self-contained module that does one thing (e.g., a blog app, a user authentication app, or in our case, a To-Do app).

Creating the Project

From inside your mycrudproject directory (where your virtual environment is):

django-admin startproject myproject .

The . at the end tells Django to create the project files in the current directory, rather than creating an extra myproject folder.

This command creates a few important files:
* manage.py: A command-line utility for interacting with your Django project.
* myproject/: This directory contains your project’s settings, URL configurations, and more.

Creating Your First App

Let’s create our To-Do app:

python manage.py startapp todo_app

This creates a new todo_app directory with its own set of files, including models.py, views.py, admin.py, etc.

Registering Your App

Django needs to know about the new app. Open myproject/settings.py and add 'todo_app' to the INSTALLED_APPS list:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'todo_app',  # Our new app!
]

Building the To-Do Model (Create & Read Foundation)

The model is where you define the structure of your data. In our To-Do app, each To-Do item will have a title and a description.

Defining Your Data Structure (models.py)

Open todo_app/models.py and add the following code:

from django.db import models

class Todo(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, null=True)
    completed = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title
  • Supplementary Explanation: Model
    In Django, a “model” is a Python class that defines the structure of data that will be stored in your database. Each attribute (like title, description) in the class represents a column in a database table. Django’s powerful Object-Relational Mapper (ORM) allows you to interact with your database using Python code instead of raw SQL.

Here’s what these fields mean:
* title: A short text field for the To-Do’s title. max_length is required for CharField.
* description: A longer text field. blank=True means it’s optional in forms, and null=True means it can be empty in the database.
* completed: A true/false field, defaulting to False.
* created_at: Automatically stores the date and time when the To-Do is created.
* __str__(self): This method tells Django how to represent a Todo object as a string, which is helpful in the admin panel.

Making and Applying Migrations

Whenever you change your models, you need to tell Django to update your database schema.

  • Supplementary Explanation: Migrations
    “Migrations” are Django’s way of propagating changes you make to your models (like adding a new field or a new model) into your database schema. Django generates Python files that describe these changes, and you apply them to your database.

  • Make migrations: This command creates the migration files based on your models.py changes.
    bash
    python manage.py makemigrations

  • Apply migrations: This command executes the migration files, creating the Todo table in your database.
    bash
    python manage.py migrate

    This also applies migrations for Django’s built-in apps (like user authentication).

Accessing Your Data via Admin Panel

Django provides an incredible built-in admin interface that lets you manage your database data easily.

  1. Create a superuser: This user will have full access to the admin panel.
    bash
    python manage.py createsuperuser

    Follow the prompts to create a username, email, and password.

  2. Register your model: For your Todo model to appear in the admin panel, you need to register it. Open todo_app/admin.py and add:
    “`python
    # todo_app/admin.py

    from django.contrib import admin
    from .models import Todo

    admin.site.register(Todo)
    “`

  3. Run the development server:
    bash
    python manage.py runserver

    Open your web browser and go to http://127.0.0.1:8000/admin/. Log in with the superuser credentials you just created. You should now see “Todos” under the “TODO_APP” section. Click on “Todos” and then “Add Todo” to create a few sample To-Do items.

Creating Your Views, Templates, and URLs (Read, Create, Update, Delete)

Now, let’s build the user-facing parts of our application.

  • Supplementary Explanation: View
    A “view” in Django is a Python function or class that receives a web request (like someone visiting a URL) and returns a web response (like an HTML page). It’s where your application’s logic resides, deciding what data to fetch and what template to render.

  • Supplementary Explanation: Template
    A “template” is a file (usually HTML) that defines the structure and layout of the web page. Django templates allow you to embed Python variables and logic directly into your HTML, making them dynamic.

  • Supplementary Explanation: URL
    A “URL” (Uniform Resource Locator) is the web address that users type into their browser. In Django, you map specific URLs to specific views, telling Django which view function to run when a certain address is visited.

Creating Forms for Data Input

Django has a powerful forms system. We’ll use a ModelForm which automatically creates a form from our Todo model.

Create a new file todo_app/forms.py:

from django import forms
from .models import Todo

class TodoForm(forms.ModelForm):
    class Meta:
        model = Todo
        fields = ['title', 'description', 'completed']

Defining Your Views (todo_app/views.py)

Open todo_app/views.py and replace its content with the following:

from django.shortcuts import render, redirect, get_object_or_404
from .models import Todo
from .forms import TodoForm

def todo_list(request):
    """
    Displays a list of all To-Do items. (Read operation)
    """
    todos = Todo.objects.all().order_by('-created_at')
    return render(request, 'todo_app/todo_list.html', {'todos': todos})

def todo_create(request):
    """
    Handles creating a new To-Do item. (Create operation)
    """
    if request.method == 'POST':
        form = TodoForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('todo_list')
    else:
        form = TodoForm()
    return render(request, 'todo_app/todo_form.html', {'form': form, 'page_title': 'Add New To-Do'})

def todo_update(request, pk):
    """
    Handles updating an existing To-Do item. (Update operation)
    """
    todo = get_object_or_404(Todo, pk=pk)
    if request.method == 'POST':
        form = TodoForm(request.POST, instance=todo)
        if form.is_valid():
            form.save()
            return redirect('todo_list')
    else:
        form = TodoForm(instance=todo) # Pre-fill form with existing data
    return render(request, 'todo_app/todo_form.html', {'form': form, 'page_title': 'Edit To-Do'})

def todo_delete(request, pk):
    """
    Handles deleting a To-Do item. (Delete operation)
    """
    todo = get_object_or_404(Todo, pk=pk)
    if request.method == 'POST':
        todo.delete()
        return redirect('todo_list')
    # For simplicity, we'll just confirm deletion on a POST request
    # In a real app, you might render a confirmation page first
    return render(request, 'todo_app/todo_confirm_delete.html', {'todo': todo})

Designing Your Templates

First, tell Django where to find your app’s templates. Create a new directory structure todo_app/templates/todo_app/.
* mycrudproject/todo_app/templates/todo_app/

Now, create the HTML files inside todo_app/templates/todo_app/:

todo_list.html (for viewing To-Dos)

<!-- mycrudproject/todo_app/templates/todo_app/todo_list.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My To-Do List</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        .todo-item { border: 1px solid #eee; padding: 10px; margin-bottom: 10px; }
        .todo-item h3 { margin-top: 0; }
        .actions a { margin-right: 10px; text-decoration: none; color: blue; }
        .actions a:hover { text-decoration: underline; }
        .completed { text-decoration: line-through; color: gray; }
        .add-link { display: block; margin-bottom: 20px; text-decoration: none; color: green; font-weight: bold;}
        .add-link:hover { text-decoration: underline; }
    </style>
</head>
<body>
    <h1>My To-Do List</h1>
    <a href="{% url 'todo_create' %}" class="add-link">Add New To-Do</a>

    {% if todos %}
        {% for todo in todos %}
            <div class="todo-item {% if todo.completed %}completed{% endif %}">
                <h3>{{ todo.title }}</h3>
                {% if todo.description %}
                    <p>{{ todo.description }}</p>
                {% endif %}
                <p><small>Created: {{ todo.created_at|date:"M d, Y P" }}</small></p>
                <div class="actions">
                    <a href="{% url 'todo_update' pk=todo.pk %}">Edit</a>
                    <a href="{% url 'todo_delete' pk=todo.pk %}">Delete</a>
                </div>
            </div>
        {% endfor %}
    {% else %}
        <p>No To-Do items yet. Why not add one?</p>
    {% endif %}
</body>
</html>
  • Supplementary Explanation: {% ... %} and {{ ... }} in Templates
    {% ... %} are “template tags” that execute logic (like if statements or for loops).
    {{ ... }} are “template variables” that display data passed from your Django views.

todo_form.html (for creating/updating To-Dos)

<!-- mycrudproject/todo_app/templates/todo_app/todo_form.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ page_title }}</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        form div { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input[type="text"], textarea { width: 300px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; }
        input[type="checkbox"] { margin-right: 5px; }
        button { padding: 10px 15px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
        button:hover { background-color: #0056b3; }
        .back-link { display: block; margin-top: 20px; text-decoration: none; color: blue; }
        .back-link:hover { text-decoration: underline; }
    </style>
</head>
<body>
    <h1>{{ page_title }}</h1>
    <form method="post">
        {% csrf_token %} {# Django requires this for security when submitting forms #}
        {{ form.as_p }} {# Renders each form field inside a <p> tag #}
        <button type="submit">Save To-Do</button>
    </form>
    <a href="{% url 'todo_list' %}" class="back-link">Back to List</a>
</body>
</html>

todo_confirm_delete.html (for deleting To-Dos)

<!-- mycrudproject/todo_app/templates/todo_app/todo_confirm_delete.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Confirm Delete</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        .delete-btn { background-color: #dc3545; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; }
        .delete-btn:hover { background-color: #c82333; }
        .cancel-link { margin-left: 15px; text-decoration: none; color: blue; }
        .cancel-link:hover { text-decoration: underline; }
    </style>
</head>
<body>
    <h1>Confirm Deletion</h1>
    <p>Are you sure you want to delete the To-Do: "<strong>{{ todo.title }}</strong>"?</p>
    <form method="post">
        {% csrf_token %}
        <button type="submit" class="delete-btn">Yes, delete it</button>
        <a href="{% url 'todo_list' %}" class="cancel-link">Cancel</a>
    </form>
</body>
</html>

Mapping URLs

We need to create URL patterns for our views.

  1. Create todo_app/urls.py: This file doesn’t exist by default in the app. Create it:
    “`python
    # todo_app/urls.py

    from django.urls import path
    from . import views

    urlpatterns = [
    path(”, views.todo_list, name=’todo_list’),
    path(‘create/’, views.todo_create, name=’todo_create’),
    path(‘update//’, views.todo_update, name=’todo_update’),
    path(‘delete//’, views.todo_delete, name=’todo_delete’),
    ]
    ``
    * **Supplementary Explanation:
    pkin URLs**pkstands for "primary key," which is a unique identifier for each record in a database table.tells Django to expect an integer value in this part of the URL and pass it as an argument namedpk` to the view function.

  2. Include app URLs in project URLs: Open myproject/urls.py and add an include statement:

    “`python

    myproject/urls.py

    from django.contrib import admin
    from django.urls import path, include # Import include

    urlpatterns = [
    path(‘admin/’, admin.site.urls),
    path(‘todos/’, include(‘todo_app.urls’)), # Include our app’s URLs
    ]
    ``
    Now, any URL starting with
    /todos/will be handed over totodo_app/urls.py` to be matched.

Running Your App!

You’ve built a full CRUD application! Let’s see it in action.

Make sure your virtual environment is active and run the development server:

python manage.py runserver

Open your browser and navigate to http://127.0.0.1:8000/todos/.

You should see your To-Do list!
* Click “Add New To-Do” to create new items.
* Click “Edit” next to an item to update its details.
* Click “Delete” to remove an item.

Conclusion

Congratulations! You’ve successfully built your first simple CRUD application using Django. You’ve learned how to:
* Set up a Django project and app.
* Define data models and use migrations.
* Interact with the Django admin panel.
* Create views to handle web requests.
* Design HTML templates to display data and forms.
* Map URLs to connect everything together.

This is just the beginning of your Django journey. From here, you can explore adding user authentication, more complex models, advanced forms, styling with CSS, and much more. Keep experimenting, and happy coding!

Comments

Leave a Reply