Building Your First Portfolio Website with Django: A Beginner’s Guide

Have you ever wanted a place online to showcase your awesome projects, skills, or creative work? A portfolio website is the perfect solution! It’s your personal corner of the internet where you can impress potential employers, clients, or collaborators.

In this guide, we’re going to build a simple portfolio website using Django. Django is a powerful and popular web framework for Python. Think of a web framework as a complete toolkit that helps you build websites much faster and more efficiently than starting from scratch. Django is known for its “batteries-included” philosophy, meaning it comes with many features built-in, like an admin panel and database management, which are super helpful, especially for beginners.

By the end of this tutorial, you’ll have a functional website that can display a list of your projects, complete with titles, descriptions, and even images!

Why Django for a Portfolio?

Django offers several benefits that make it a great choice for your portfolio:

  • Python-based: If you already know or are learning Python, Django will feel familiar.
  • Fast Development: Django helps you get features up and running quickly thanks to its conventions and built-in tools.
  • Scalable: While we’re starting small, Django can handle websites with millions of users, so your portfolio can grow with you.
  • Secure: Django takes security seriously, helping to protect your website from common vulnerabilities.
  • Rich Ecosystem: A large community means lots of resources, libraries, and support are available.

Let’s dive in and start building!

Prerequisites

Before we begin, make sure you have the following installed on your computer:

  • Python 3: Django requires Python. You can download it from the official Python website.
  • pip: This is Python’s package installer, usually included with Python 3. We’ll use it to install Django.
  • A Text Editor or IDE: Something like VS Code, Sublime Text, or Atom will be perfect for writing your code.
  • Basic Terminal/Command Prompt Knowledge: We’ll be running commands to set up our project.

Setting Up Your Development Environment

It’s good practice to create a virtual environment for each of your Python projects. Think of a virtual environment as a secluded bubble where you install project-specific Python packages (like Django). This prevents conflicts between different projects that might require different versions of the same package.

1. Create a Project Directory

First, create a folder for your project and navigate into it using your terminal.

mkdir my_portfolio
cd my_portfolio

2. Create a Virtual Environment

Inside your my_portfolio directory, run the following command to create a virtual environment named venv (you can name it anything, but venv is common):

python -m venv venv
  • python -m venv: This command uses Python’s built-in venv module to create a virtual environment.
  • venv: This is the name of the folder that will contain your virtual environment files.

3. Activate the Virtual Environment

Now, activate your virtual environment. The command depends on your operating system:

On macOS/Linux:

source venv/bin/activate

On Windows (Command Prompt):

venv\Scripts\activate.bat

On Windows (PowerShell):

venv\Scripts\Activate.ps1

You’ll know it’s active when you see (venv) at the beginning of your terminal prompt.

4. Install Django

With your virtual environment activated, install Django using pip:

pip install django Pillow
  • pip install django: This installs the Django web framework.
  • Pillow: This is a library Django uses to handle image uploads. We’ll need it because our portfolio projects will have images.

Creating Your Django Project

Now that Django is installed, let’s create our main project.

1. Start the Project

In your my_portfolio directory (where manage.py will live), run:

django-admin startproject portfolio_project .
  • django-admin: This is Django’s command-line utility.
  • startproject portfolio_project: This tells Django to create a new project named portfolio_project.
  • . (the dot): This crucial dot tells Django to create the project files in the current directory, rather than creating another nested folder.

After running this, your my_portfolio directory should look something like this:

my_portfolio/
├── venv/
├── manage.py
└── portfolio_project/
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
  • manage.py: A command-line utility that interacts with your Django project. You’ll use this a lot!
  • portfolio_project/: This is the main configuration folder for your entire website.
    • settings.py: Contains all your project’s settings and configurations.
    • urls.py: Defines the “map” of your website, telling Django which functions to run when a specific URL is visited.

2. Run Initial Migrations

Django uses a database to store information. The migrate command sets up the initial database tables that Django needs to function (like user accounts, sessions, etc.).

python manage.py migrate

This will create a db.sqlite3 file in your my_portfolio directory. This is a simple, file-based database perfect for development.

3. Test Your Server

Let’s make sure everything is working by starting Django’s development server:

python manage.py runserver

You should see output similar to this:

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.
August 24, 2023 - 14:30:00
Django version 4.2.4, using settings 'portfolio_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Open your web browser and go to http://127.0.0.1:8000/. You should see a “The install worked successfully! Congratulations!” page. This means your Django project is up and running!

You can stop the server at any time by pressing CTRL+C in your terminal.

Creating Your First Django App: projects

A Django project can contain multiple apps. Think of a project as the entire car, and apps as different components like the engine, the dashboard, or the wheels. Each app is a self-contained module that does one thing well. For our portfolio, we’ll create an app called projects to manage our portfolio items.

1. Start the App

Make sure you are in the my_portfolio directory (where manage.py is located) and your virtual environment is active. Then run:

python manage.py startapp projects

This creates a new projects directory inside your my_portfolio folder, with its own set of files:

my_portfolio/
├── venv/
├── manage.py
├── portfolio_project/
└── projects/
    ├── migrations/
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── tests.py
    └── views.py

2. Register the App

Django needs to know about your new app. Open portfolio_project/settings.py and find the INSTALLED_APPS list. Add 'projects' to it:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'projects', # Add your new app here
]

Defining Your Portfolio Content (Models)

Models are how Django interacts with your database. Each model is essentially a Python class that defines the structure of a table in your database. For our portfolio, we’ll create a Project model to store information about each of your portfolio items.

1. Create the Project Model

Open projects/models.py and add the following code:

from django.db import models

class Project(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField()
    image = models.ImageField(upload_to='project_images/')
    project_url = models.URLField(blank=True, null=True)

    def __str__(self):
        return self.title

Let’s break down what we added:

  • class Project(models.Model):: We define a class named Project that inherits from models.Model. This tells Django it’s a model.
  • title = models.CharField(max_length=200): This creates a field for the project’s title. CharField is for short text, and max_length is required to specify its maximum length.
  • description = models.TextField(): This creates a field for a longer block of text for the project’s description.
  • image = models.ImageField(upload_to='project_images/'): This field is for uploading image files. upload_to specifies a subdirectory within our MEDIA_ROOT where uploaded images will be stored.
  • project_url = models.URLField(blank=True, null=True): This field stores a URL for the project (e.g., a link to the live demo or GitHub repository). blank=True means the field isn’t mandatory in forms, and null=True means the database can store NULL values for this field if it’s empty.
  • def __str__(self):: This special method defines how an object of this class will be represented as a string. It’s helpful for readability in the Django admin panel.

2. Configure Media Files

Since we’re uploading images, Django needs to know where to store them and how to access them. Open portfolio_project/settings.py and add these lines at the bottom:

import os # Add this line at the very top of the file if not already present


MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  • MEDIA_URL: This is the URL prefix that will be used to serve media files. For example, http://127.0.0.1:8000/media/project_images/my_project.jpg.
  • MEDIA_ROOT: This is the absolute path to the directory where user-uploaded media files will be stored on your server. os.path.join(BASE_DIR, 'media') creates a media folder right inside your main project directory.

3. Create and Apply Migrations

Whenever you make changes to your models (models.py), you need to do two things:

  1. Make migrations: Tell Django to create the necessary instructions to change your database schema based on your model changes.
  2. Apply migrations: Execute those instructions to actually update your database.

Run these commands in your terminal:

python manage.py makemigrations projects
python manage.py migrate
  • makemigrations projects: This tells Django to look at the projects app and create a new migration file (e.g., 0001_initial.py) inside projects/migrations/. This file describes how to create the Project table in your database.
  • migrate: This command applies all pending migrations to your database, creating the Project table.

Making Your Data Accessible (Django Admin)

Django comes with a powerful, ready-to-use administrative interface. It’s fantastic for managing content (like your portfolio projects) without writing custom code.

1. Create a Superuser

To access the admin panel, you need an administrator account (a “superuser”).

python manage.py createsuperuser

Follow the prompts to create a username, email, and password. Make sure to remember them!

2. Register Your Model with the Admin

Open projects/admin.py and tell Django to make your Project model visible and editable in the admin interface:

from django.contrib import admin
from .models import Project

admin.site.register(Project)

3. Explore the Admin Panel

Start your development server again:

python manage.py runserver

Go to http://127.0.0.1:8000/admin/ in your browser. Log in with the superuser credentials you just created.

You should now see “Projects” listed under the “PROJECTS” section. Click on “Projects” and then “Add project” to add a few sample projects. Upload some images for them too!

Displaying Your Portfolio (Views and URLs)

Now that we have data in our database, we need a way to display it on our website. This involves views (Python functions that handle web requests) and URLs (the web addresses that trigger those views).

1. Create a View to List Projects

Open projects/views.py and add the following code:

from django.shortcuts import render
from .models import Project

def project_list(request):
    # Fetch all Project objects from the database
    projects = Project.objects.all()

    # Create a dictionary to pass data to the template
    context = {'projects': projects}

    # Render the 'project_list.html' template, passing the context
    return render(request, 'projects/project_list.html', context)
  • from django.shortcuts import render: render is a shortcut function to load a template, fill it with data, and return an HttpResponse.
  • from .models import Project: We import our Project model so we can interact with it.
  • def project_list(request):: This is our view function. It takes a request object (which contains information about the user’s web request) as an argument.
  • projects = Project.objects.all(): This is a powerful command! Project.objects is Django’s Object-Relational Mapper (ORM). It allows us to interact with our database using Python objects instead of writing raw SQL. all() fetches every Project record from the database.
  • context = {'projects': projects}: We create a dictionary called context. The keys of this dictionary (here, 'projects') will be the variable names we can use in our template.
  • return render(request, 'projects/project_list.html', context): This tells Django to load the HTML file located at projects/project_list.html, insert the projects data into it, and send the resulting HTML back to the user’s browser.

2. Map URLs to Your View

We need to tell Django which URL should trigger our project_list view. This is done in urls.py files.

First, create a new urls.py file inside your projects app directory: projects/urls.py.

from django.urls import path
from . import views # Import the views from the current app

urlpatterns = [
    path('', views.project_list, name='project_list'), # Map the root URL of this app to our view
]
  • path('', views.project_list, name='project_list'): This line defines a URL pattern.
    • '': This means an empty string, which represents the root URL of this particular app.
    • views.project_list: This is the view function we want to call when this URL is accessed.
    • name='project_list': This gives a name to our URL pattern. It’s useful for referring to this URL dynamically in templates and other parts of our code, rather than hardcoding the URL itself.

Next, we need to include our projects app’s URLs in the main project’s urls.py file. Open portfolio_project/urls.py and modify it:

from django.contrib import admin
from django.urls import path, include
from django.conf import settings # Import settings
from django.conf.urls.static import static # Import static function

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('projects.urls')), # Include URLs from our 'projects' app
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  • from django.urls import path, include: We import include to pull in URL patterns from other urls.py files.
  • path('', include('projects.urls')): This tells Django that any request to the root URL of our entire project (/) should be handled by the urls.py file inside our projects app.
  • if settings.DEBUG: urlpatterns += static(...): This block is crucial for making our uploaded images (media files) accessible in development. static() is a helper function that tells Django where to find and serve files located in MEDIA_ROOT when requested via MEDIA_URL. Remember: This setup is only for development and should not be used in a production environment.

Making It Pretty (Templates)

Templates are essentially HTML files with special Django template tags and variables that allow you to display dynamic data from your views.

1. Create a Template Directory

Django looks for templates in a specific structure. Inside your projects app, create a templates folder, and inside that, another projects folder. This is a common convention to prevent template name conflicts between different apps.

my_portfolio/
├── ...
└── projects/
    ├── ...
    └── templates/
        └── projects/
            └── project_list.html

2. Create the project_list.html Template

Now, open projects/templates/projects/project_list.html and add this basic HTML structure:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Awesome Portfolio</title>
    <style>
        /* A little inline CSS to make it look decent for now */
        body { font-family: Arial, sans-serif; margin: 20px; line-height: 1.6; background-color: #f4f4f4; color: #333; }
        h1 { color: #0056b3; text-align: center; margin-bottom: 40px; }
        .portfolio-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px; max-width: 1200px; margin: 0 auto; }
        .project-card { background-color: white; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); overflow: hidden; }
        .project-card img { width: 100%; height: 200px; object-fit: cover; }
        .project-content { padding: 20px; }
        .project-content h2 { margin-top: 0; color: #007bff; }
        .project-content p { font-size: 0.9em; color: #555; }
        .project-content a { display: inline-block; background-color: #007bff; color: white; padding: 8px 15px; border-radius: 5px; text-decoration: none; margin-top: 10px; }
        .project-content a:hover { background-color: #0056b3; }
        .no-projects { text-align: center; color: #777; margin-top: 50px; }
    </style>
</head>
<body>
    <h1>My Awesome Portfolio</h1>

    <div class="portfolio-grid">
        <!-- Django template tag: {% for %} loop to iterate over projects -->
        {% for project in projects %}
            <div class="project-card">
                {% if project.image %}
                    <!-- Display project image if available -->
                    <img src="{{ project.image.url }}" alt="{{ project.title }}">
                {% endif %}
                <div class="project-content">
                    <h2>{{ project.title }}</h2>
                    <p>{{ project.description }}</p>
                    {% if project.project_url %}
                        <!-- Display project URL if available -->
                        <a href="{{ project.project_url }}" target="_blank">View Project</a>
                    {% endif %}
                </div>
            </div>
        {% empty %}
            <!-- This block runs if 'projects' list is empty -->
            <p class="no-projects">No projects added yet!</p>
        {% endfor %}
    </div>
</body>
</html>

Here’s what’s happening with the Django template language:

  • {% for project in projects %}: This is a for loop that iterates over the projects list that we passed from our project_list view in the context dictionary. In each iteration, the current project object is assigned to the project variable.
  • {{ project.title }}, {{ project.description }}, etc.: These are template variables. Django replaces them with the actual values from the project object (e.g., the title, description, or URL of the current project).
  • {% if project.image %}: This is an if statement. It checks if project.image exists (i.e., if an image was uploaded for that project).
  • {{ project.image.url }}: This specifically gets the URL of the uploaded image file.
  • {% empty %}: This is a special part of the for loop that displays its content if the projects list is empty.
  • The inline CSS (<style>...</style>) is just there to give your portfolio a basic, readable look without needing to set up static files for CSS yet.

Running Your Website

Now, let’s see your beautiful portfolio come to life!

Make sure your virtual environment is active and you are in the my_portfolio directory (where manage.py is).

python manage.py runserver

Open your web browser and go to http://127.0.0.1:8000/. You should now see the “My Awesome Portfolio” page displaying the projects you added through the admin panel! If you don’t see any projects, go back to the admin (/admin/) and add some.

What’s Next?

Congratulations! You’ve successfully built a basic portfolio website using Django. This is just the beginning. Here are some ideas for what you can do next:

  • Enhance Styling: Replace the inline CSS with proper static files (CSS, JavaScript) to make your site look much better. You might even explore CSS frameworks like Bootstrap or Tailwind CSS.
  • Add a Contact Page: Create another app or view for a contact form so visitors can get in touch with you.
  • Detail Pages: Create individual pages for each project with more detailed information.
  • About Page: Add an “About Me” page to introduce yourself.
  • Deployment: Learn how to deploy your Django website to a live server so others can see it on the internet. Services like Heroku, Vercel, or DigitalOcean are popular choices.
  • Version Control: Learn Git and GitHub to track your code changes and collaborate with others.

Django is a vast and rewarding framework to learn. Keep experimenting, building, and exploring its capabilities!


Comments

Leave a Reply