Skip to content

First Django Project

This chapter will guide you through creating your first Django project, understanding the basic structure of a Django project, and running your first web application.

Creating a Django Project

Using django-admin to Create a Project

bash
# Make sure the virtual environment is activated
(venv) $ django-admin startproject mysite

# View the created project structure
cd mysite
tree .  # Linux/macOS
# or
dir /s  # Windows

Project Structure Analysis

mysite/
├── manage.py           # Django project management script
└── mysite/            # Project configuration package
    ├── __init__.py    # Python package identifier
    ├── settings.py    # Project settings file
    ├── urls.py        # URL configuration file
    ├── asgi.py        # ASGI configuration file
    └── wsgi.py        # WSGI configuration file

manage.py Detailed Explanation

python
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys

def main():
    """Run administrative tasks."""
    # Set Django settings module
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)

if __name__ == '__main__':
    main()

Main uses of manage.py:

  • Run development server
  • Create applications
  • Execute database migrations
  • Create superuser
  • Collect static files

settings.py Detailed Explanation

python
# mysite/settings.py
"""
Django settings for mysite project.

Generated by 'django-admin startproject' using Django 4.2.7.
"""

from pathlib import Path

# Project root directory
BASE_DIR = Path(__file__).resolve().parent.parent

# Security key - should be kept secret in production
SECRET_KEY = 'django-insecure-your-secret-key-here'

# Debug mode - should be set to False in production
DEBUG = True

# List of allowed hosts
ALLOWED_HOSTS = []

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',          # Admin interface
    'django.contrib.auth',           # Authentication system
    'django.contrib.contenttypes',   # Content types framework
    'django.contrib.sessions',       # Session framework
    'django.contrib.messages',       # Message framework
    'django.contrib.staticfiles',    # Static files management
]

# Middleware configuration
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# URL configuration
ROOT_URLCONF = 'mysite.urls'

# Template configuration
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# WSGI application
WSGI_APPLICATION = 'mysite.wsgi.application'

# Database configuration
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Password validation
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
LANGUAGE_CODE = 'en-us'  # English
TIME_ZONE = 'UTC'  # UTC timezone
USE_I18N = True
USE_TZ = True

# Static files (CSS, JavaScript, Images)
STATIC_URL = 'static/'

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

urls.py Detailed Explanation

python
# mysite/urls.py
"""mysite URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path

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

Running Development Server

Starting the Server

bash
# In the project root directory (directory containing manage.py)
python manage.py runserver

# Output information
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

December 15, 2023 - 10:30:00
Django version 4.2.7, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Accessing the Website

Open your browser and visit http://127.0.0.1:8000/, you should see the Django welcome page:

html
<!-- Django welcome page content -->
The install worked successfully! Congratulations!

You are seeing this message because this Django installation is working correctly.

Next, start your first app by running python manage.py startapp [app_label].

Custom Server Configuration

bash
# Specify port
python manage.py runserver 8080

# Specify IP and port
python manage.py runserver 0.0.0.0:8000

# Use different settings file
python manage.py runserver --settings=mysite.settings_dev

Database Initialization

Applying Initial Migrations

bash
# Apply database migrations
python manage.py migrate

# Output information
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

Creating a Superuser

bash
# Create admin account
python manage.py createsuperuser

# Enter information as prompted
Username (leave blank to use 'yourname'): admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.

Accessing Admin Interface

Visit http://127.0.0.1:8000/admin/ and log in using the superuser account you just created.

Creating Your First App

Django Project vs App

Project
├── App 1 (App) - Blog functionality
├── App 2 (App) - User management
├── App 3 (App) - Comment system
└── Project configuration

Project: Container for the entire website App: Python package that implements specific functionality

Creating an App

bash
# Create an app named polls
python manage.py startapp polls

# View app structure
tree polls/  # Linux/macOS

App Structure Analysis

polls/
├── __init__.py        # Python package identifier
├── admin.py          # Admin interface configuration
├── apps.py           # App configuration
├── migrations/       # Database migration files
│   └── __init__.py
├── models.py         # Data models
├── tests.py          # Test files
└── views.py          # View functions

App Files Detailed Explanation

apps.py - App Configuration

python
# polls/apps.py
from django.apps import AppConfig

class PollsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'polls'
    verbose_name = 'Polls App'  # Display name in admin interface

models.py - Data Models

python
# polls/models.py
from django.db import models

# Create your models here.

views.py - View Functions

python
# polls/views.py
from django.shortcuts import render

# Create your views here.

admin.py - Admin Interface

python
# polls/admin.py
from django.contrib import admin

# Register your models here.

Writing Your First View

Creating View Functions

python
# polls/views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

def detail(request, question_id):
    return HttpResponse(f"You're looking at question {question_id}.")

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse(f"You're voting on question {question_id}.")

Configuring URL Routing

1. Create App URL Configuration

python
# polls/urls.py (new file)
from django.urls import path
from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

2. Include App URLs in Project URL Configuration

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

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

Registering the App

python
# mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',  # Add polls app
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Testing Views

bash
# Start development server
python manage.py runserver

# Visit these URLs to test
http://127.0.0.1:8000/polls/
http://127.0.0.1:8000/polls/34/
http://127.0.0.1:8000/polls/34/results/
http://127.0.0.1:8000/polls/34/vote/

URL Configuration Details

URL Pattern Syntax

python
from django.urls import path, re_path
from . import views

urlpatterns = [
    # Basic path
    path('', views.index),
    
    # Path with parameters
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<slug:slug>/', views.article_detail),
    
    # Regex path
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    
    # Optional parameters
    path('blog/', views.blog_index),
    path('blog/page/<int:num>/', views.blog_index),
]

Path Converters

python
# Django built-in path converters
str     # Matches any non-empty string except '/'
int     # Matches positive integers, including 0
slug    # Matches letters, numbers, hyphens, underscores
uuid    # Matches formatted UUID
path    # Matches any non-empty string, including path separator '/'

# Usage examples
urlpatterns = [
    path('articles/<int:year>/', views.year_archive),
    path('articles/<str:title>/', views.article_detail),
    path('users/<uuid:user_id>/', views.user_profile),
    path('files/<path:file_path>/', views.file_download),
]

Custom Path Converters

python
# converters.py
class FourDigitYearConverter:
    regex = '[0-9]{4}'

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return '%04d' % value

# urls.py
from django.urls import path, register_converter
from . import views, converters

register_converter(converters.FourDigitYearConverter, 'yyyy')

urlpatterns = [
    path('articles/<yyyy:year>/', views.year_archive),
]

URL Naming and Reverse Resolution

python
# urls.py
from django.urls import path
from . import views

app_name = 'polls'  # App namespace
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
python
# Use in views
from django.urls import reverse
from django.http import HttpResponseRedirect

def vote(request, question_id):
    # ... voting logic ...
    return HttpResponseRedirect(reverse('polls:results', args=(question_id,)))
html
<!-- Use in templates -->
<a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a>

Project Configuration Optimization

Environment Variable Configuration

python
# settings.py
import os
from pathlib import Path

# Read configuration from environment variables
DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
SECRET_KEY = os.environ.get('SECRET_KEY', 'your-default-secret-key')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')

# Database configuration
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# If DATABASE_URL environment variable is set, use it
DATABASE_URL = os.environ.get('DATABASE_URL')
if DATABASE_URL:
    import dj_database_url
    DATABASES['default'] = dj_database_url.parse(DATABASE_URL)

Separate Configuration Files

mysite/
├── settings/
│   ├── __init__.py
│   ├── base.py        # Base configuration
│   ├── development.py # Development environment configuration
│   ├── production.py  # Production environment configuration
│   └── testing.py     # Testing environment configuration
python
# settings/base.py
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent.parent

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls.apps.PollsConfig',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'mysite.urls'
WSGI_APPLICATION = 'mysite.wsgi.application'

# ... other common configurations
python
# settings/development.py
from .base import *

DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Development tools
INSTALLED_APPS += [
    'debug_toolbar',
    'django_extensions',
]

MIDDLEWARE += [
    'debug_toolbar.middleware.DebugToolbarMiddleware',
]

INTERNAL_IPS = ['127.0.0.1']
python
# settings/production.py
from .base import *
import os

DEBUG = False
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

# Security configuration
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'

Using Different Configurations

bash
# Development environment
python manage.py runserver --settings=mysite.settings.development

# Production environment
python manage.py migrate --settings=mysite.settings.production

# Or set environment variable
export DJANGO_SETTINGS_MODULE=mysite.settings.development
python manage.py runserver

Common Management Commands

Project Management Commands

bash
# Create project
django-admin startproject mysite

# Create app
python manage.py startapp myapp

# Run development server
python manage.py runserver
python manage.py runserver 8080
python manage.py runserver 0.0.0.0:8000

# Check project
python manage.py check
python manage.py check --deploy  # Deployment check

Database Management Commands

bash
# Create migration files
python manage.py makemigrations
python manage.py makemigrations myapp

# Apply migrations
python manage.py migrate
python manage.py migrate myapp

# View migration status
python manage.py showmigrations

# View SQL statements
python manage.py sqlmigrate myapp 0001

User Management Commands

bash
# Create superuser
python manage.py createsuperuser

# Change user password
python manage.py changepassword username

Other Useful Commands

bash
# Collect static files
python manage.py collectstatic

# Clear sessions
python manage.py clearsessions

# Enter Django shell
python manage.py shell

# Run tests
python manage.py test
python manage.py test myapp

# Generate secret key
python manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

Project Deployment Preparation

Production Environment Checklist

python
# Security check
python manage.py check --deploy

# Common check items
SECURITY_WARNING = [
    'DEBUG = False',
    'SECRET_KEY must not be exposed',
    'ALLOWED_HOSTS must be set',
    'HTTPS configuration',
    'CSRF protection',
    'XSS protection',
]

requirements.txt

bash
# Generate dependencies file
pip freeze > requirements.txt

# requirements.txt content example
Django==4.2.7
psycopg2-binary==2.9.7
gunicorn==21.2.0
whitenoise==6.6.0
python-decouple==3.8

Static Files Configuration

python
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'

STATICFILES_DIRS = [
    BASE_DIR / 'static',
]

# Use WhiteNoise for static files
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # Add this line
    # ... other middleware
]

# Static files compression
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Chapter Summary

This chapter covered creating your first Django project in detail:

Key Points:

  • Project Creation: Use django-admin startproject to create a project
  • Project Structure: Understand Django's file organization
  • App Creation: Use manage.py startapp to create apps
  • URL Configuration: Set up URL routing and view mapping
  • Development Server: Run and test Django applications

Important Concepts:

  • Project vs App: Project is the container, app is the functional module
  • MVT Architecture: Model-View-Template design pattern
  • URL Routing: Map URLs to view functions
  • Configuration Management: Use settings.py to manage project configuration

Best Practices:

  • Create separate apps for each feature
  • Use meaningful URL patterns and names
  • Separate configuration files for different environments
  • Use environment variables to manage sensitive information
  • Follow Django project structure conventions

Development Workflow:

  1. Create project and app
  2. Configure URL routing
  3. Write view functions
  4. Test functionality
  5. Optimize configuration

In the next chapter, we will dive deeper into Django's basic concepts, including settings, middleware, app configuration, and other core knowledge.

Further Reading

Content is for learning and research only.