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-invenvmodule 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 namedportfolio_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 namedProjectthat inherits frommodels.Model. This tells Django it’s a model.title = models.CharField(max_length=200): This creates a field for the project’s title.CharFieldis for short text, andmax_lengthis 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_tospecifies a subdirectory within ourMEDIA_ROOTwhere 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=Truemeans the field isn’t mandatory in forms, andnull=Truemeans the database can storeNULLvalues 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 amediafolder 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:
- Make migrations: Tell Django to create the necessary instructions to change your database schema based on your model changes.
- 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 theprojectsapp and create a new migration file (e.g.,0001_initial.py) insideprojects/migrations/. This file describes how to create theProjecttable in your database.migrate: This command applies all pending migrations to your database, creating theProjecttable.
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:renderis a shortcut function to load a template, fill it with data, and return anHttpResponse.from .models import Project: We import ourProjectmodel so we can interact with it.def project_list(request):: This is our view function. It takes arequestobject (which contains information about the user’s web request) as an argument.projects = Project.objects.all(): This is a powerful command!Project.objectsis Django’s Object-Relational Mapper (ORM). It allows us to interact with our database using Python objects instead of writing raw SQL.all()fetches everyProjectrecord from the database.context = {'projects': projects}: We create a dictionary calledcontext. 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 atprojects/project_list.html, insert theprojectsdata 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 importincludeto pull in URL patterns from otherurls.pyfiles.path('', include('projects.urls')): This tells Django that any request to the root URL of our entire project (/) should be handled by theurls.pyfile inside ourprojectsapp.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 inMEDIA_ROOTwhen requested viaMEDIA_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 aforloop that iterates over theprojectslist that we passed from ourproject_listview in thecontextdictionary. In each iteration, the current project object is assigned to theprojectvariable.{{ project.title }},{{ project.description }}, etc.: These are template variables. Django replaces them with the actual values from theprojectobject (e.g., the title, description, or URL of the current project).{% if project.image %}: This is anifstatement. It checks ifproject.imageexists (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 theforloop that displays its content if theprojectslist 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!
Leave a Reply
You must be logged in to post a comment.