How Your Host Browser Talks to a Django Container
In Part 6 we mastered serving a Vite front-end and talking to the outside world. Now let’s flip things around: run a Django backend in Docker and hit its API from your laptop, Postman, or browser using localhost. You’ll see how port binding bridges the gap between your container and your desktop — and how to use Docker Compose for fast, modern Django dev!
Learning Aims
By the end of this post you will be able to:
Understand how Docker connects containerized apps to your laptop via localhost.
Use Docker Compose to manage Django development with hot reload, environment variables, and dependency isolation.
See how a simple CRUD API in Django can be tested from any desktop HTTP client — just as if it was running natively.
1. Project Overview
Your folder structure:
docker-container-to-localhost/
├─ Dockerfile
├─ docker-compose.yml
├─ requirements.txt
├─ .env
├─ manage.py
├─ todo_proj/
└─ todos/
The core: a Django backend serving an in-memory todo API at /todos/.
2. Docker Concepts to Learn
Dockerfile: Django, the Right Way
FROM python:3.12-slim
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
A Dockerfile
is a text document that contains all the commands a user could call on the command line to assemble an image.
Command | Description |
---|---|
FROM python:3.12-slim |
This sets the base image for our container. We are using the official Python 3.12 slim image, which is a lightweight version of Python. |
WORKDIR /usr/src/app |
This sets the working directory inside the container to /usr/src/app . All subsequent commands will be run from this directory. |
COPY requirements.txt ./ |
This copies the requirements.txt file from our local machine to the current working directory (/usr/src/app ) inside the container. |
RUN pip install --upgrade pip && pip install -r requirements.txt |
This command first upgrades pip to the latest version and then installs all the Python dependencies listed in the requirements.txt file. |
COPY . . |
This copies the rest of our project's code from our local machine to the current working directory (/usr/src/app ) inside the container. |
EXPOSE 8000 |
This informs Docker that the container will listen on port 8000 at runtime. |
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] |
This specifies the command to run when the container starts. It will start the Django development server and make it accessible from outside the container. |
docker-compose.yml
version: "3.9"
services:
api:
build: .
container_name: docker-container-to-localhost
env_file: .env
command: python manage.py runserver 0.0.0.0:8000
ports:
- "${HOST_PORT}:8000" # Host:Container
volumes:
- .:/usr/src/app # Live code reload
- /usr/local/lib/python3.12/site-packages # Anonymous deps cache
stdin_open: true
tty: true
docker-compose.yml
is a YAML file that defines how Docker containers should be created, configured, and linked together.
Command | Description |
---|---|
version: "3.9" |
This specifies the version of the Docker Compose file format we are using. |
services: |
This is where we define the different services (containers) that make up our application. |
api: |
This is the name of our service. We can name it anything we want. |
build: . |
This tells Docker Compose to build the image for this service using the Dockerfile in the current directory. |
container_name: docker-container-to-localhost |
This sets a custom name for our container. |
env_file: .env |
This tells Docker Compose to load environment variables from a file named .env in the current directory. |
command: python manage.py runserver 0.0.0.0:8000 |
This overrides the default command in the Dockerfile . |
ports: |
This maps ports between the host machine and the container. |
- "${HOST_PORT}:8000" |
This maps the port specified by the HOST_PORT environment variable on the host machine to port 8000 on the container. |
volumes: |
This mounts host paths or named volumes, specified as sub-options to a service. |
- .:/usr/src/app |
This mounts the current directory on the host machine to /usr/src/app in the container. This is great for development as changes to your code on the host will be reflected in the container. |
- /usr/local/lib/python3.12/site-packages |
This creates an anonymous volume to cache the installed python packages. |
stdin_open: true |
This is equivalent to the -i flag in the docker run command. It keeps STDIN open even if not attached. |
tty: true |
This is equivalent to the -t flag in the docker run command. It allocates a pseudo-TTY. |
3. How to Run and Test the Project
To run and test the project, you will need to have Docker and Docker Compose installed on your machine.
-
Build and run the container:
docker-compose up -d --build
* `docker-compose`: The command to run Docker Compose.
* `up`: This command builds, (re)creates, starts, and attaches to containers for a service.
* `-d`: This runs the containers in detached mode, meaning they will run in the background.
* `--build`: This forces Docker Compose to build the image before starting the containers.
-
Create the database schema:
docker-compose exec api python manage.py migrate
* `docker-compose exec`: This command executes a command in a running container.
* `api`: The name of the service (container) we want to run the command in.
* `python manage.py migrate`: The command to create the database schema.
-
Create a superuser to access the admin panel:
docker-compose exec api python manage.py createsuperuser
* Follow the prompts to create a username, email, and password.
- Test the application:
* Open your web browser and go to http://localhost:8000
(or the port you specified in your .env
file). You should see the Django welcome page.
- Go to
http://localhost:8000/admin
and log in with the superuser credentials you just created. You should be able to access the Django admin panel.
- Go to
http://localhost:8000/todos
-
GET
-> See all todos
-
POST
-> Create a new todo
-
PUT
-> Update a todo
-
DELETE
-> Delete a todo
Port binding (HOST:CONTAINER) is how you connect containers to your real desktop world. This is true for front-ends, APIs, and databases.
No need for localhost hacks — Docker does the network translation for you!
Best practice for teams — Everyone runs the same isolated dev stack, with no Python/Node install headaches.
5. Conclusion
From this project, you have learned:
✅ How to bind a container’s internal port to your computer’s localhost
✅ That 0.0.0.0 in your app tells it to listen for external connections
✅ Compose lets you manage all this with a simple, readable YAML
✅ Hot reload, isolated dependencies, interactive shells, and easy config — all standard!
This project provides a solid foundation for using Docker in your Python projects. You can now explore more advanced topics like using Docker for production deployments, multi-container applications, and more.
Top comments (0)