Static Files
Static Files — CSS, JavaScript, images, fonts, PDFs, etc. The files that make your site look beautiful and modern instead of plain HTML.
Many beginners either:
- hardcode inline styles forever (messy)
- put CSS in <style> tags in every template (DRY violation)
- or get stuck with “404 not found” errors when deploying because static files don’t work the same in development and production
Today we’re going to fix all that — step by step — like I’m sitting next to you, creating folders, writing files, and testing together.
We’ll make your polls app look professional with proper CSS, images, and JavaScript.
Goal for Today
By the end, you’ll have:
- A clean static/ folder structure
- CSS that applies globally (from base.html)
- A logo image in the header
- Page-specific JavaScript (e.g. vote counter animation)
- Working in both development (runserver) and ready for production (collectstatic)
Step 1: Understand Django’s Static Files Philosophy
Django has two modes:
| Mode | Command | Where files are served from | When used |
|---|---|---|---|
| Development | python manage.py runserver | Each app’s static/ folder + project STATICFILES_DIRS | Daily work |
| Production | Real web server (nginx, etc.) | One big folder after collectstatic | Deployment |
Golden rule: Always develop with the same structure you’ll use in production.
Step 2: Create the Standard Static Folder Structure
In your project root (next to manage.py):
|
0 1 2 3 4 5 6 7 8 9 |
mkdir -p static/css mkdir -p static/js mkdir -p static/images mkdir -p static/fonts # optional |
Now create app-specific static (recommended for reusability):
|
0 1 2 3 4 5 6 7 8 |
mkdir -p polls/static/polls/css mkdir -p polls/static/polls/js mkdir -p polls/static/polls/images |
Why the extra polls/ inside? → Namespacing — prevents conflicts if two apps have style.css
Final structure:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
mysite-project/ ├── manage.py ├── static/ ← project-level (global) │ ├── css/ │ │ └── global.css │ ├── js/ │ └── images/ │ └── logo.png ├── polls/ │ └── static/ │ └── polls/ │ ├── css/ │ │ └── polls.css │ ├── js/ │ └── images/ │ └── poll-icon.png └── ... |
Step 3: Add Settings for Static Files
Open mysite/settings.py
Make sure these are present (they usually are by default):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent # Static files (CSS, JavaScript, Images) STATIC_URL = '/static/' # URL prefix # Development: where to find static files STATICFILES_DIRS = [ BASE_DIR / "static", # project-level static # BASE_DIR / "polls" / "static", # if you want app-specific too (optional) ] # Production: where collectstatic puts everything STATIC_ROOT = BASE_DIR / "staticfiles" # created by collectstatic |
Step 4: Create Some Real Static Files
Global CSS: static/css/global.css
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/* Global styles – applied to every page */ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f8f9fa; color: #333; margin: 0; } .container { max-width: 1100px; margin: 0 auto; padding: 0 1.5rem; } .btn { display: inline-block; padding: 0.8rem 1.6rem; background: #006400; color: white; border-radius: 6px; text-decoration: none; font-weight: 500; transition: background 0.2s; } .btn:hover { background: #004d00; } .card { background: white; padding: 1.8rem; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.08); margin-bottom: 1.5rem; } |
App-specific CSS: polls/static/polls/css/polls.css
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* Polls-specific styles */ .poll-card h3 { margin-top: 0; color: #006400; } .vote-badge { background: #28a745; color: white; padding: 4px 10px; border-radius: 20px; font-size: 0.85rem; } |
A logo image
Download any small PNG (or create placeholder) → static/images/logo.png
Step 5: Load & Use Static Files in Templates
In templates/base.html (your master template):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
{% load static %} <!-- ← VERY IMPORTANT – at top, after extends if any --> <head> ... <!-- Global CSS --> <link rel="stylesheet" href="{% static 'css/global.css' %}"> <!-- App-specific CSS --> <link rel="stylesheet" href="{% static 'polls/css/polls.css' %}"> <!-- Page-specific CSS --> {% block extra_css %}{% endblock %} </head> <body> <header> <img src="{% static 'images/logo.png' %}" alt="Polls Logo" height="50"> <h1>Hyderabad Polls 2026</h1> </header> {% block content %}{% endblock %} <!-- Global JS --> <script src="{% static 'js/global.js' %}"></script> <!-- Page-specific JS --> {% block extra_js %}{% endblock %} </body> |
Step 6: Test in Development
|
0 1 2 3 4 5 6 |
python manage.py runserver |
Visit any page → you should see:
- Logo in header
- Global styles (fonts, colors)
- Polls-specific styles
- No 404 errors in browser console
Common error: 404 for static files
Fixes:
- Did you add {% load static %} at top?
- Is STATICFILES_DIRS correct?
- Restart server after adding files
Step 7: Production – collectstatic
When deploying:
|
0 1 2 3 4 5 6 |
python manage.py collectstatic |
→ Copies all static files from everywhere into STATIC_ROOT (staticfiles/ folder)
Then configure your web server (nginx, Apache, Whitenoise) to serve /static/ from there.
Your Quick Practice Task (Do This Right Now)
-
Create the folders and files as shown
-
Add {% load static %} to base.html
-
Add global CSS link and logo image
-
Create polls/static/polls/css/polls.css with some style (e.g. .poll-card { border-left: 5px solid #006400; })
-
In index.html → add class to cards → see style apply
-
Add a small JS file static/js/alert.js:
JavaScript0123456alert("Static JS works!");Include it → reload → see alert
Tell me what feels next:
- “Done! Now show me how to use images in templates (user uploads later)”
- “How to use Bootstrap/Tailwind via CDN or local files?”
- “What is Whitenoise for production static files?”
- “Got 404 on static – here’s error”
- Or ready for Forms + Voting + POST + F()?
You now have a professional, maintainable static files setup — your site is starting to look like a real product.
You’re doing fantastic — let’s keep going! 🚀🇮🇳
