Skip to content

A developers profile web page to show off your favourite projects. Each project shows live GitHub stats. Uses Django, Tailwind, HTMX and Alpine.js

License

Notifications You must be signed in to change notification settings

seapagan/django-projects

Repository files navigation

Django Projects Portfolio

A modern Django application for showcasing your development projects. Built with Django 5.1 and styled with Tailwind CSS, this application provides a clean and responsive interface to display your portfolio of projects.

All the About, Skills, Social links and Projects are fully dynamic from the database, no code editing should be needed to get your profile up and running.

There is a live example of this portfolio app at https://www.gnramsay.com

Features

  • 🚀 Built with Django 5.1
  • 💅 Modern UI with Tailwind CSS. We use django-tailwind-cli to make the integration easier. This uses the Tailwind CLI and does NOT require Node.js to be installed
  • 🧩 Component-based templates using django-cotton and django-shadcn
  • 👤 Custom Models and Admin pages to customize the settings and text
  • 📝 Contact form with Google reCAPTCHA v2 integration for spam protection and stored in the database as well as sent by email to the site owner
  • 🔒 Environment-based configuration with customization from the database
  • 🛠️ Modern development tools integration (uv, pre-commit, ruff, mypy)
  • 📱 Fully responsive design
  • 🌓 Light/Dark mode options, with a dropdown for user preference or system setting.
  • 💾 Optional caching using memcached for improved performance
  • 🔄 Live browser reload during development
  • 🔐 Enhanced security features for production deployment
  • 🚀 Production-ready with gunicorn integration
  • 📄 Dynamic pagination of projects using HTMX for smooth, server-side loading
  • 🚫 Custom error pages (400, 403, 404, 500) for better user experience

Requirements

  • Python 3.10+

Other package requirements will be automatically installed with the dependencies.

Installation

Using uv (Recommended)

  1. Clone the repository:
git clone https://github.com/seapagan/django-projects
cd django-projects
  1. Install dependencies using uv:
uv venv
uv sync --no-dev
source .venv/bin/activate # On Windows: .venv\Scripts\activate

Using Traditional pip/venv

  1. Clone the repository:
git clone https://github.com/seapagan/django-projects
cd django-projects
  1. Create and activate a virtual environment:
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. Install Python dependencies:
pip install -r requirements.txt

Configuration

Environment Variables

The application uses further environment variables for configuration and security. Most of them do have a default setting that will be used if not specified.

Key settings:

  • DJANGO_SECRET_KEY: Your Django secret key. This MUST be set to a secure string.
  • DJANGO_DEBUG: Set to 1 for development, 0 for production
  • DJANGO_SECURE_MODE: Set to 1 to enable enhanced security features for production (see Security Features section)
  • DJANGO_CSRF_TRUSTED_ORIGINS: JSON array of trusted origins for CSRF protection, e.g. ["https://www.myserver.com"]
  • DJANGO_ALLOWED_HOSTS: JSON array of allowed hosts, e.g. [".myserver.com"]
  • DJANGO_STATIC_ROOT: Path where static files will be collected in production mode
  • DJANGO_USE_CACHE: Set to 1 to enable caching for the whole application. This uses memcached and that needs to be installed locally. Defaults to 0 (better for development) See the Caching secton below.
  • DJANGO_CACHE_TIMEOUT: Cache expiry length, in seconds (Defaults to 600, 10 minutes)
  • DJANGO_PROTECT_ADMIN: Set to 1 to enable IP-based admin access restriction. If not set or set to 0, all IPs can access the admin panel
  • DJANGO_ADMIN_IPS_ALLOWED: JSON array of IP addresses allowed to access the admin panel, e.g. ["127.0.0.1", "192.168.1.100"]. If not set, defaults to ["127.0.0.1", "localhost"]. Only used when DJANGO_PROTECT_ADMIN is set to 1

Note

If you do specify a value of DJANGO_ADMIN_IPS_ALLOWED, the defaults are REMOVED. Should you still want the defaults, they need to be manually added to the env var along with your custom addresses.

  • DJANGO_SECURE_PROXY: Set to 1 if you are using a secure reverse proxy (which passes the X_FORWARDED_FOR header) to serve this app
  • RECAPTCHA_SITE_KEY: Your Google reCAPTCHA v2 site key
  • RECAPTCHA_SECRET_KEY: Your Google reCAPTCHA v2 secret key

PostgreSQL Database (Optional)

By default, the application uses SQLite for the database. However, you can configure it to use PostgreSQL instead by setting the following environment variables:

  • DJANGO_USE_POSTGRES: Set to 1 to use PostgreSQL instead of SQLite
  • DJANGO_POSTGRES_DB: PostgreSQL database name
  • DJANGO_POSTGRES_USER: PostgreSQL username
  • DJANGO_POSTGRES_PASSWORD: PostgreSQL password
  • DJANGO_POSTGRES_HOST: PostgreSQL host (default: localhost)
  • DJANGO_POSTGRES_PORT: PostgreSQL port (default: 5432)

Note

The PostgreSQL user and database must already exist, and the user needs to have ownership (or access) to that database.

For SQLite, the local database file will be created when the migrations are run.

Important

This project uses the binary version of psycopg which is not compatible with some older systems (primarily older Macs or if using PyPy Python). If you encounter compatibility issues, you should remove the psycopg[binary] package and use the plain psycopg package instead, or compile it locally. For more information, see the psycopg documentation on supported systems.

Email Settings (Optional)

You can configure the email (SMTP) server to send contact emails using the below environment variables:

  • USE_LIVE_EMAIL: Set to 1 to send actual emails, 0 or unset to output to console
  • EMAIL_HOST: SMTP server host (required if USE_LIVE_EMAIL=1)
  • EMAIL_PORT: SMTP server port (required if USE_LIVE_EMAIL=1)
  • EMAIL_HOST_USER: SMTP username (required if USE_LIVE_EMAIL=1)
  • EMAIL_HOST_PASSWORD: SMTP password (required if USE_LIVE_EMAIL=1)
  • EMAIL_USE_TLS: Set to 1 to use TLS for SMTP (optional, defaults to 1)
  • DEFAULT_FROM_EMAIL: Default sender email address (required if USE_LIVE_EMAIL=1)
  • CONTACT_FORM_RECIPIENT: Email address where contact form submissions will be sent (required if USE_LIVE_EMAIL=1)

.env File

Create an .env file in the project root with the following content, or set the environment variables directly:

DJANGO_SECRET_KEY=your-secret-key
DJANGO_DEBUG=1 # sets debug mode
DJANGO_SECURE_MODE=0 # set to 1 for production security features

# Database settings (optional - defaults to SQLite if not set)
DJANGO_USE_POSTGRES=0 # set to 1 to use PostgreSQL
DJANGO_POSTGRES_DB=mydatabase
DJANGO_POSTGRES_USER=myuser
DJANGO_POSTGRES_PASSWORD=your-postgres-password
DJANGO_POSTGRES_HOST=localhost
DJANGO_POSTGRES_PORT=5432

# Production settings (required when DJANGO_DEBUG=0)
DJANGO_CSRF_TRUSTED_ORIGINS=["https://www.myserver.com"]
DJANGO_ALLOWED_HOSTS=[".myserver.com"]
DJANGO_STATIC_ROOT="/var/www/myproject/static/"

# cache settings
DJANGO_USE_CACHE=0 # set to 0 for development, 1 for production when the database rarely changes
DJANGO_CACHE_TIMEOUT=3600 # defaults to 600 (10 minutes) if not set

# admin IP whitelist
DJANGO_PROTECT_ADMIN=1 # set to 1 to enable IP-based admin access restriction
DJANGO_ADMIN_IPS_ALLOWED=["127.0.0.1", "192.168.1.100"] # IP addresses allowed to access admin panel

# enable secure proxy forwarding. This ALSO needs 'DJANGO_SECURE_MODE=1'
DJANGO_SECURE_PROXY=0 # set to 1 if you are serving behind a secure proxy (ie nginx etc)

# recaptcha settings
RECAPTCHA_SITE_KEY=your-recaptcha-site-key
RECAPTCHA_SECRET_KEY=your-recaptcha-secret-key

# Email settings (optional - if USE_LIVE_EMAIL=0, emails will output to console only)
USE_LIVE_EMAIL=1
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_HOST_USER[email protected]
EMAIL_HOST_PASSWORD=your-smtp-password
EMAIL_USE_TLS=1
DEFAULT_FROM_EMAIL[email protected]
CONTACT_FORM_RECIPIENT[email protected]

Note

There is an .example.env file in the project root you can rename and modify to your own settings

To get your reCAPTCHA keys (required for the contact form functionality):

  1. Visit the Google reCAPTCHA Admin Console
  2. Sign in with your Google account
  3. Click the "+" button to create a new site
  4. Choose "reCAPTCHA v2" and "I'm not a robot" Checkbox
  5. Add your domain(s) to the list (you can use '127.0.0.1' for local testing, be sure to add the correct domain when you deploy)
  6. Copy the "Site Key" to RECAPTCHA_SITE_KEY and "Secret Key" to RECAPTCHA_SECRET_KEY

Note

For a Production or User-Facing project, ALWAYS set DJANGO_DEBUG=0

Usage

  1. Apply database migrations:
python manage.py migrate
  1. Create a superuser:
python manage.py createsuperuser
  1. Run the development server:
python manage.py tailwind runserver
  1. Visit http://localhost:8000/admin to add your projects
  2. View your portfolio at http://localhost:8000

Add your Projects, Personal Details and skills

You can customize the portfolio with your own skills and projects through the Django Admin interface at http://localhost:8000/admin

Customizing the About Section

You can add and manage about sections through the Django admin interface in the Site Configuration section. Each about section has the following field:

  • Content: The main text content for this section. This field supports multiple paragraphs and can include limited HTML tags.

About sections are linked to your site configuration and allow you to provide detailed information about yourself, your background, skills, and experience. Each about record will be in a separate paragraph - you can use limited HTML tags in this field (a,strong,em,ul,ol,li,sub,sup - all others will be stripped.)

If you have no about sections added, the About area will not be displayed.

Adding Projects

You can add projects by clicking on the Projects section in the admin pages. Each project has the following fields:

  • Title: The name of your project (maximum 100 characters)
  • Details: A detailed description of your project. This field supports multiple paragraphs and can be left blank if needed
  • Priority: An optional integer value that determines the display order (lower numbers appear first)
  • Repository URL: The URL to your project's source code repository (optional)
  • Website URL: The URL to your project's live website or demo (optional)
  • Tags: Associate relevant tags with your project to categorize it (optional). You first have to add the tags in the Tags section of the Admin page.

Projects are displayed on your portfolio page in the following order:

  1. Projects with a priority value are shown first, sorted by priority (lower numbers appear first and duplicate priorities are sorted by their created_at date.)
  2. Projects without a priority value are then displayed, sorted by creation date (oldest to newest)

You can set a project's priority in the admin interface. This allows you to highlight your most important projects by giving them lower priority numbers.

App Settings

The application provides additional configuration options through the Django admin interface at the Site Configuration section . These settings allow you to customize various aspects of your portfolio:

  • Site Content

    • owner_name: The Owner of the site. This will be the page title and the text in the header of the page content (default: "The Developer")
    • hero_title: The main title displayed on your portfolio (default: "Full Stack Developer")
    • hero_info: Primary text content for the hero section (up to 500 characters, no default)
    • hero_secondary: Secondary text content for the hero section (up to 500 characters, no default)
  • Social Media Links

    • github_username: Your GitHub username
    • twitter_username: Your Twitter/X username
    • linkedin_username: Your LinkedIn username
    • youtube_username: Your YouTube channel username
    • medium_username: Your Medium username

    Any social media usernames left blank will not be displayed on your portfolio.

  • About Section

    As mentioned above you can add/edit your 'About' info here too.

  • Languages and Frameworks

    You can manage your programming languages and frameworks through the Django admin interface by editing the Site Configuration database.

    • Languages : Add programming languages you work with

      • name: Name of the programming language (e.g., "Python", "JavaScript")
    • Frameworks (/admin/app/framework/): Add frameworks and libraries you work with

      • name: Name of the framework (e.g., "Django", "React")

    Both languages and frameworks will be displayed on your portfolio to showcase your technical stack. If you have none added, the whole My SKills section will not be displayed.

These settings can be modified at any time through the admin interface and changes will be reflected immediately on your portfolio (though, see the note below on Caching)

Contact Form

The contact form will save each contact into the database and you can view these in the Admin pages in the Contact Submissions section.

Optionally, if you have set up the email, each contact will also be emailed to you as it is submitted.

Caching

This Django application is set up for optional caching which is disabled by default. Generally it is not much use when you are setting up or customizing the database since any changes will take 10 minutes to actually be visible in the front-end. It is a bit overkill for this application but a good skill to learn.

Note

Probably best not to enable this until your database is set up to your liking, as the default is a 10 minute cache time-out. See below how to change this.

I have chosen to use memcached for this, though you can use Redis, File Caching, Local Memory or any other method that Django supports. See the Django docs on Caching for more info.

You need to install memcached for this to work. If this is not installed and the cache enabled your application will crash.

See the link above for how to install for your server, under Debian/Ubuntu it is available as a package:

sudo apt install memcached

Finally, to enable the caching, set the below variable in your .env file or environment:

DJANGO_USE_CACHE=1

If this variable is 0 or missing, caching will be disabled.

You can change the length of time that the database is cached by setting the below variable:

DJANGO_CACHE_TIMEOUT=1200 # Default is 600 (10 Minutes)

Production Deployment

For production deployment, it's recommended to:

  1. Set DJANGO_DEBUG=0 to disable debug mode
  2. Set DJANGO_SECURE_MODE=1 to enable security features

Caution

The Secure Mode settings may need tweaking for your exact use-case. As it stands, they work well for an application served behind an nginx reverse-proxy (which is a GREAT way to serve your Django App) but may cause issues in other cases. Checkout the config/settings.py file around the end to see what settings are set and add/adjust any that you need for your specific setup.

  1. Use PostgreSQL instead of SQLite by setting DJANGO_USE_POSTGRES=1 and configuring the related database settings
  2. Set DJANGO_PROTECT_ADMIN=1 to enable IP-based admin access restriction and configure DJANGO_ADMIN_IPS_ALLOWED with trusted IP addresses
  3. Configure the production-specific environment variables:
    • DJANGO_CSRF_TRUSTED_ORIGINS: Your domain(s) as a JSON array
    • DJANGO_ALLOWED_HOSTS: Your domain(s) as a JSON array
    • DJANGO_STATIC_ROOT: The path where static files will be collected

You should also run the collectstatic files before deployment:

python manage.py collectstatic

Tip

This is a customized collectstatic command which, as well as the usual functionality will also:

  • build the Tailwind production file
  • minimize any Javascript files in the assets/js folder.

You no longer need to run the python manage.py tailwind build command seperately.

The application includes gunicorn for production deployment. A typical command to run the application in production would be:

gunicorn config.wsgi:application --bind 0.0.0.0:8000

For a proper production setup, you should:

  1. Run gunicorn as a systemd service for automatic startup and monitoring
  2. Use Nginx as a reverse proxy in front of gunicorn to handle static files, SSL, and more

For a detailed guide on setting up Django with Nginx and Gunicorn in production, see: https://realpython.com/django-nginx-gunicorn/

Security Features

When DJANGO_SECURE_MODE=1 (and DJANGO_DEBUG=0), the following security features are enabled:

  • HTTP Strict Transport Security (HSTS) - Initially set to 30 seconds for testing, with a commented option to increase to 15552000 seconds (180 days) once you've verified everything works correctly

Caution

Be very careful when setting the HSTS timeout to a longer value (like 180 days). Once set, it can be almost impossible to change later as browsers will remember this setting for the specified duration. However, setting a longer timeout is highly recommended once you've verified that HSTS is working correctly for your site.

  • Secure cookies for CSRF and sessions
  • SSL redirection
  • Secure referrer policy
  • Permissions policy headers that restrict potentially dangerous browser features
  • IP-based admin access restriction - When DJANGO_PROTECT_ADMIN=1, only allows specified IP addresses to access the admin panel
  • Secure Proxy forwarding - When DJANGO_SECURE_PROXY=1, your proxy needs to support this.

These features follow Django security best practices and help protect your application against common web vulnerabilities.

Project Structure

├── app/               # Main application code
├── assets/            # Static assets
│   └── css/           # CSS files
│   └── js/            # JavaScript files
│   └── favicon.ico    # Put your favicon here or use the existing one
├── config/            # Project configuration
├── templates/         # HTML templates
│   ├── app/           # Application templates
│   └── cotton/        # Component templates
└── manage.py          # Django management script

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development

This project uses several development tools to maintain code quality:

  • pre-commit hooks for code formatting and linting
  • ruff for Python linting
  • mypy for type-checking
  • django-browser-reload for live development
  • django-stubs for improved type checking

Install development dependencies and set up pre-commit:

Using uv (Recommended):

uv sync
pre-commit install

Using pip:

pip install -r requirements-dev.txt
pre-commit install

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A developers profile web page to show off your favourite projects. Each project shows live GitHub stats. Uses Django, Tailwind, HTMX and Alpine.js

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •