The recording for this lesson has not been published yet.
Your tutorial blog is yours, and you should keep it. But from lesson 1.1 onwards the notes
will say things like "open blog/managers.py" - and that only works if we agree
on what the project looks like today. The starter repository is that agreement: the Django
Girls blog, unchanged in behaviour, with nothing added yet.
Get it running now. Every later lesson assumes you can start this project in under a minute.
git clone https://github.com/example/more-about-django-starter.git myblog
cd myblog
git log --oneline -3
The last command should show three commits and nothing else. A short history is deliberate: in lesson 0.3 you will add your own commits on top and be able to tell them apart at a glance.
That works too, as long as you rename the project package to mysite and the
app to blog. Everything else in the course is written against those two
names.
A virtual environment is a directory with its own python and its own
site-packages. Installing into it cannot break another project and cannot
break your operating system's Python. One environment per project, always, and never
committed to git.
python -m venv .venv
# Linux and macOS
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\Activate.ps1
# Windows cmd
.venv\Scripts\activate.bat
Your prompt now starts with (.venv). Verify that you are really inside it
before installing anything:
which python # .../myblog/.venv/bin/python (Windows: where python)
python -V # Python 3.12.x
pip -V # pip ... from .../myblog/.venv/lib/...
python -m pip install --upgrade pip
pip install -r requirements.txt
Open the file. Every line has an exact version, and that is the point.
# requirements.txt
Django==5.2.6
django-environ==0.12.0
Pillow==11.3.0
| Specifier | Means | Use it for |
|---|---|---|
Django==5.2.6 |
Exactly this release | Applications, and anything you deploy |
Django~=5.2.0 |
5.2.x, patch releases allowed | Security fixes without surprises |
Django>=5.2 |
Anything newer, including 6.0 | Libraries, rarely applications |
Django |
Whatever exists today | Nothing you care about |
Unpinned dependencies mean your laptop, your colleague's laptop and the server can each run a different Django, and the bug only shows up on one of them. Pinning turns "it works on my machine" into a reproducible fact. When you add a package yourself:
pip install django-extensions
pip freeze > requirements.txt # then read the diff before committing
It writes out every package in the environment, including things you installed to try
once. Keep development-only tools such as ruff and pytest in a
separate dev-requirements.txt.
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
migrate creates db.sqlite3 and applies every migration in the
repository - Django's own tables plus blog. It is safe to run twice;
the second time it reports that there is nothing to do.
Now visit both of these and confirm they work:
http://127.0.0.1:8000/ - the post list, empty for nowhttp://127.0.0.1:8000/admin/ - log in with the superuser and add two posts,
remembering to set published_dateOptional, but it makes the next modules more interesting: load the sample posts that ship with the repository.
python manage.py loaddata blog/fixtures/sample_posts.json
myblog/
├── .git/ # the repository itself - never edit by hand
├── .gitignore # what git must ignore (lesson 0.3)
├── .venv/ # your virtual environment - ignored by git
├── README.md # how to run the project; keep it true
├── requirements.txt # pinned runtime dependencies
├── dev-requirements.txt # linters, pytest - not needed in production
├── manage.py # thin wrapper that sets DJANGO_SETTINGS_MODULE
├── db.sqlite3 # your local database - ignored by git
├── mysite/ # the project package
│ ├── __init__.py
│ ├── settings.py # one file for now; split in lesson 1.3
│ ├── urls.py # root URLconf: admin + include("blog.urls")
│ ├── wsgi.py # entry point for Gunicorn (module 14)
│ └── asgi.py # entry point for async servers (module 12)
├── blog/ # the only app so far
│ ├── __init__.py
│ ├── admin.py # admin.site.register(Post)
│ ├── apps.py # BlogConfig - we use it properly in lesson 1.1
│ ├── forms.py # PostForm
│ ├── models.py # Post
│ ├── urls.py # app_name = "blog" + four routes
│ ├── views.py # post_list, post_detail, post_new, post_edit
│ ├── tests.py # empty; replaced by a package in module 8
│ ├── migrations/ # 0001_initial.py - committed, always
│ ├── fixtures/ # sample_posts.json
│ └── templates/blog/ # post_list.html, post_detail.html, post_edit.html
├── templates/ # project-wide templates
│ └── base.html
└── static/ # your CSS and JS
└── css/blog.css
Three files are worth opening straight away.
manage.py does almost nothing: it points
DJANGO_SETTINGS_MODULE at mysite.settings and hands the arguments
to Django. When you later have two settings modules, this is the line that decides the
default.mysite/settings.py still has DEBUG = True and a
hard-coded SECRET_KEY, exactly like the tutorial. That is intentional -
lessons 1.2 and 1.3 fix it and you should see the "before" state.blog/migrations/0001_initial.py is code, not a build
artefact. It is committed, and it must stay committed, or nobody else can create the
database.| Message | Cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named 'django' |
The environment is not activated, or you installed into a different one | Activate .venv, check which python, install again |
command not found: python |
Your system only exposes python3 |
Use python3 -m venv .venv; inside the venv python
works |
Activate.ps1 cannot be loaded |
PowerShell execution policy | Set-ExecutionPolicy -Scope CurrentUser RemoteSigned |
You have unapplied migrations |
You skipped migrate |
Run python manage.py migrate |
no such table: blog_post |
The database file exists but is empty | Run migrate; locally you may also delete
db.sqlite3 and start over |
Error: That port is already in use |
Another runserver is still alive |
Stop it, or python manage.py runserver 8001 |
TemplateDoesNotExist: blog/post_list.html |
Wrong directory, or the app is missing from INSTALLED_APPS |
Run from the folder containing manage.py; check the setting |
Two commands answer most questions before you start guessing:
python manage.py check # configuration problems, no server needed
python manage.py showmigrations # which migrations are applied, per app
It is single-threaded, reloads on every file change and serves static files itself. Never put it in front of real users - module 14 shows you what to use instead.
.venv, install the requirements and
get the post list rendering in your browser.blog/views.py that explains why.python manage.py runserver again and read
the error. Then reactivate it. Recognising this error saves you hours later.requirements.txt to an older Django patch release,
reinstall, and check python -c "import django; print(django.get_version())".
Put it back afterwards.README.md. Then follow your own instructions in a fresh folder.