Chapter 18: Getting Started with Django

Django is a full-featured web framework. Build data-driven web apps efficiently.

Project: Server Inventory

A web app to track infrastructure. Users register servers and log events.

Setting Up Django

Virtual Environment

mkdir server_inventory && cd server_inventory
python -m venv .venv
source .venv/bin/activate

Installing Django

pip install django

Creating the Project

django-admin startproject inv_project .

Project structure:

server_inventory/
├── .venv/
├── inv_project/
│   ├── __init__.py
│   ├── settings.py      # Project configuration
│   ├── urls.py          # URL routing
│   ├── asgi.py
│   └── wsgi.py
└── manage.py            # Django commands

Creating the Database

python manage.py migrate

Creates db.sqlite3 with Django’s tables.

Running the Development Server

python manage.py runserver

Creating an App

python manage.py startapp inventory

App structure:

inventory/
├── __init__.py
├── admin.py       # Admin site config
├── apps.py        # App config
├── models.py      # Data models
├── tests.py       # Tests
└── views.py       # Request handlers

Register the App

# inv_project/settings.py
INSTALLED_APPS = [
    # My apps
    'inventory',

    # Default Django apps
    'django.contrib.admin',
    'django.contrib.auth',
    # ...
]

Defining Models

Models define data structure. Django creates database tables.

# inventory/models.py
from django.db import models

class Server(models.Model):
    """A server in the infrastructure."""
    hostname = models.CharField(max_length=100)
    ip_address = models.GenericIPAddressField()
    os = models.CharField(max_length=50, default='linux')
    status = models.CharField(max_length=20, default='active')
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.hostname} ({self.ip_address})"


class Event(models.Model):
    """An event logged for a server."""
    server = models.ForeignKey(Server, on_delete=models.CASCADE)  (1)
    timestamp = models.DateTimeField(auto_now_add=True)
    event_type = models.CharField(max_length=20)  # deploy, restart, alert
    message = models.TextField()

    class Meta:
        ordering = ['-timestamp']  (2)

    def __str__(self):
        return f"{self.server.hostname}: {self.event_type} - {self.message[:50]}"
1 Link to Server; delete events when server deleted
2 Most recent first

Migrations

Track model changes:

python manage.py makemigrations inventory
python manage.py migrate

After any model change, run both commands.

Django Admin Site

Creating Superuser

python manage.py createsuperuser

Enter username, email, password.

Registering Models

# inventory/admin.py
from django.contrib import admin
from .models import Server, Event

admin.site.register(Server)
admin.site.register(Event)

Visit 127.0.0.1:8000/admin/ to manage data.

Django Shell

Interact with models:

python manage.py shell
>>> from inventory.models import Server, Event
>>> Server.objects.all()
<QuerySet []>

>>> s = Server(hostname='web-01', ip_address='10.0.1.10')
>>> s.save()

>>> Server.objects.all()
<QuerySet [<Server: web-01 (10.0.1.10)>]>

>>> s.event_set.create(event_type='deploy', message='Initial deployment')
<Event: web-01: deploy - Initial deployment>

>>> s.event_set.all()
<QuerySet [<Event: web-01: deploy - Initial deployment>]>

Building Pages

Three components: 1. URL - Maps URL pattern to view 2. View - Processes request, returns response 3. Template - HTML with dynamic content

Project URLs

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('inventory.urls')),
]

App URLs

# inventory/urls.py
from django.urls import path
from . import views

app_name = 'inventory'
urlpatterns = [
    path('', views.index, name='index'),
    path('servers/', views.servers, name='servers'),
    path('servers/<int:server_id>/', views.server_detail, name='server_detail'),
]

Views

# inventory/views.py
from django.shortcuts import render
from .models import Server

def index(request):
    """Dashboard home."""
    return render(request, 'inventory/index.html')

def servers(request):
    """List all servers."""
    servers = Server.objects.order_by('hostname')
    context = {'servers': servers}
    return render(request, 'inventory/servers.html', context)

def server_detail(request, server_id):
    """Show server details and events."""
    server = Server.objects.get(id=server_id)
    events = server.event_set.all()
    context = {'server': server, 'events': events}
    return render(request, 'inventory/server_detail.html', context)

Templates

Create directory: inventory/templates/inventory/

<!-- inventory/templates/inventory/base.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Server Inventory</title>
</head>
<body>
    <nav>
        <a href="{% url 'inventory:index' %}">Dashboard</a>
        <a href="{% url 'inventory:servers' %}">Servers</a>
    </nav>

    {% block content %}{% endblock content %}
</body>
</html>
<!-- inventory/templates/inventory/index.html -->
{% extends 'inventory/base.html' %}

{% block content %}
<h1>Infrastructure Dashboard</h1>
<p>Track servers, log events, monitor your infrastructure.</p>
{% endblock content %}
<!-- inventory/templates/inventory/servers.html -->
{% extends 'inventory/base.html' %}

{% block content %}
<h1>Servers</h1>

<table>
    <tr>
        <th>Hostname</th>
        <th>IP</th>
        <th>OS</th>
        <th>Status</th>
    </tr>
    {% for server in servers %}
    <tr>
        <td>
            <a href="{% url 'inventory:server_detail' server.id %}">
                {{ server.hostname }}
            </a>
        </td>
        <td>{{ server.ip_address }}</td>
        <td>{{ server.os }}</td>
        <td>{{ server.status }}</td>
    </tr>
    {% empty %}
    <tr><td colspan="4">No servers registered.</td></tr>
    {% endfor %}
</table>
{% endblock content %}
<!-- inventory/templates/inventory/server_detail.html -->
{% extends 'inventory/base.html' %}

{% block content %}
<h1>{{ server.hostname }}</h1>
<p>IP: {{ server.ip_address }} | OS: {{ server.os }} | Status: {{ server.status }}</p>

<h2>Events</h2>
<ul>
    {% for event in events %}
    <li>
        <strong>{{ event.timestamp|date:'Y-m-d H:i' }}</strong>
        [{{ event.event_type }}] {{ event.message }}
    </li>
    {% empty %}
    <li>No events logged.</li>
    {% endfor %}
</ul>
{% endblock content %}

Quick Reference

Command Purpose

django-admin startproject name .

Create project

python manage.py startapp name

Create app

python manage.py makemigrations

Create migrations

python manage.py migrate

Apply migrations

python manage.py createsuperuser

Create admin user

python manage.py runserver

Start dev server

python manage.py shell

Django shell

Template Tag Purpose

{% extends %}

Inherit from template

{% block %}

Define/override section

{% url 'name' %}

Generate URL

{% for %}

Loop

{% if %}

Conditional

{{ variable }}

Output value

{{ value|filter }}

Apply filter

Exercises

18-1. Service Model

Add a Service model (name, port, protocol, server FK). Display services on server detail.

18-2. Status Choices

Use Django’s choices parameter to limit status to: active, maintenance, decommissioned.

18-3. Shell Practice

Create 3 servers and 5 events via Django shell.

18-4. Search

Add a search box to filter servers by hostname.

Summary

  • Django projects contain apps with specific functionality

  • Models define data structure; migrations sync database

  • Admin site provides data management interface

  • URLs map patterns to views

  • Views process requests and return responses

  • Templates render HTML with dynamic content

  • {% extends %} enables template inheritance

Next: User input with forms.