Tuesday, April 16, 2024

Django Website with Tailwind CSS, Bootstrap, JavaScript, and GSAP

avatar

Harrinson Arrubla

@ Twitter

Welcome to my first blog. I decided to introduce a step-by-step post to duplicate this Django website. I have completed this website in the past, but I decided to start sharing my thoughts after getting in-hand with AWS and Azure. I'm not a pro right now, but it is a learning process day by day.

Description

This is a Django web application that incorporates Tailwind CSS, Bootstrap, JavaScript, and the GSAP animation library for styling and interactivity. The project includes a blog section, pages for different content types (e.g., about, timeline), and various static assets. It is under construction, so multiple features will be added using python and javascript. Why javascript? Accessing the html functionalities is "easier" using javascript rather than python until I learn how to do it properly in python.

Table of Contents

Installation

This is located in my GitHub repo where you can check the updates from now on. To start, clone the repo, create an environment, and install the requirements.txt file.

It must be said that I am used to Conda environments, and for that reason, you might find a CondaRequirements.txt file. However, I realized that it is much easier to deploy a Docker container using python environments rather than conda environments. So, I decided to include it in the building process.

Setup

This project uses sqlite3 and PostgreSQL as the database. If the settings file is not provided, you can initialize the project by creating a new settings.py file in the appropriate location and configuring the database connection details.

For example, in the your-project/website/settings.py file, add the following lines:

DATABASES = {
    'default': {
         'ENGINE': 'django.db.backends.postgresql',
         'NAME': 'your-database-name',
         'USER': 'your-username',
         'PASSWORD': 'your-password',
         'HOST': 'localhost',
         'PORT': '5432',
    }
}

Replace 'your-database-name', 'your-username', and 'your-password' with the appropriate values for your PostgreSQL setup.

Database and AWS/Azure

In my case, choosing the database is not only based on preference but in cost. Using a PostgreSQL database properly on a web server implies a new service provided by the web server "Database Management Services". Consider that before choosing the database.

Usage

In my opinion, coding, saving, and reloading the page generates a constant burnout that must be minimal at most. For that, livereload package comes in place. Additionally, tailwindcss includes the same "functionality" by using npm run dev. To run the development server, use the following commands in separate terminal windows:

npm run dev
python manage.py livereload
python manage.py runserver
  1. This command starts the Webpack development server, which watches for changes in your JavaScript and CSS files, and automatically rebuilds them when changes are detected. This is useful for efficient development and instant feedback.
npm run dev
  1. The livereload command watches for changes in your Django project files and automatically reloads the development server when changes are detected, eliminating the need to manually restart the server after each change.
python manage.py livereload
  1. This command starts the Django development server, which serves your web application and makes it accessible at http://localhost:8000 by default.
python manage.py runserver

PC and Mobile

For me, responsiveness involves a crucial part of the design, and I always try to make components as good-looking as possible. Django includes sharing and accessing when running from other devices on the same network.

python3 manage.py runserver 0.0.0.0:8000

This command starts the Django development server and binds it to the 0.0.0.0 IP address, allowing other devices on the same network to access the web application by entering the server's IP address and port in their web browsers.

Once the server is running, you can explore the different sections of the website, including the blog, about page, timeline, and other content types. The website utilizes Tailwind CSS, Bootstrap, JavaScript, and the GSAP library for styling and interactivity.

Sitemaps

Sitemaps are an essential tool for improving your website's visibility and discoverability on search engines like Google. They provide a structured way to communicate the URLs on your website to search engine crawlers, ensuring that all your content is properly indexed and accessible.

The django.contrib.sites app is required for generating fully-qualified URLs, and the django.contrib.sitemaps app provides the necessary functionality for creating and serving sitemaps.

Sitemaps for Each App

This project contains blog and pages apps. So, it is imperative to create a new file called sitemaps.py to define the sitemap classes for each app.

blog/sitemaps.py

from django.contrib.sitemaps import Sitemap
from .models import Post

class PostSitemap(Sitemap):
    changefreq = 'weekly'
    priority = 0.9
    def items(self):
        return Post.published.all()
    def lastmod(self,obj):
        return obj.updated

pages/sitemaps.py

from django.contrib.sitemaps import Sitemap
from django.urls import reverse

class StaticViewSitemap(Sitemap):
    priority = 0.5
    changefreq = "daily"

    def items(self):
        pages_views = [
                 'home_view', 'about',  
        ]
        blog_views = [
                 'post_list', 'post_list_by_tag', 'post_detail',  
        ]

        return pages_views + blog_views

    def location(self, item):
        if item in ['post_list', 'post_list_by_tag', 'post_detail']:
            if item == 'post_detail':
                return reverse('blog:post_detail', args=[2023, 4, 12, 'sample-post'])
            elif item == 'post_list_by_tag':
                return reverse('blog:post_list_by_tag', args=['sample-tag'])
            else:
                return reverse('blog:post_list')
        else:
            return reverse('pages:' + item)

Sitemaps in Project URLs

In the Django project's urls.py file, both sitemaps.py classes are included.

from django.contrib import admin
from django.urls import path, include
from django.contrib.sitemaps import views as sitemap_views

from blog.sitemaps import PostSitemap
from pages.sitemaps import StaticViewSitemap

sitemaps = {
    'post': PostSitemap,
    'static': StaticViewSitemap,
}

urlpatterns = [
# ...
    path('sitemap.xml', sitemap_views.index, {'sitemaps': sitemaps}, name='sitemap'),
    path('sitemap-<section>.xml', sitemap_views.sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
]

The sitemap.xml URL will serve an index of all available sitemaps, while sitemap-<section>.xml will serve the individual sitemap for a specific section (e.g., sitemap-post.xml or sitemap-static.xml).

Dockerization

To start, it's crucial to configure the settings.py file correctly to utilize environment variables for settings such as ALLOWED_HOSTS, SECRET_KEY, DEBUG, and DATABASES.

Ensure that you have os imported at the top of your settings.py file to utilize the os.environ.get method. This method is commonly used for setting a development environment for Django and Docker deployment, enabling you to connect your Django project to a database and configure other settings dynamically

Next, create a .env file in the root of your project to define your environment variables. This file should not be included in version control to keep your secrets safe. Here's an example .env file:

DJANGO_ALLOWED_HOSTS=localhost
SECRET_KEY=your_secret_key_here
DEBUG=1
SQL_ENGINE=django.db.backends.postgresql
SQL_DATABASE=your_database_name
SQL_USER=your_database_user
SQL_PASSWORD=your_database_password
SQL_HOST=db
SQL_PORT=5432

In case you are not using PostgreSQL but sqlite3 then omit including that information into the environment.

Why Alpine?

The Dockerfile recommended (used in this project) is configured starting with a base image of Alpine Linux version 3.18. apk, the package manager for Alpine Linux, is used for updating the package index and installs py3-pip for managing Python packages. Alpine is reliable and light making my container have the necessary packages without extra undesired information.

For more info, you can check different versions or images provided by the official docker hub link.

Executing

The docker context allows us to start the docker container using CMD. However, it is a good practice to generate some initial commands when after the docker container starts. To do so, create the ENTRYPOINT directive is set to execute the entrypoint.sh script, which contains startup commands for the Django website.

In that ENTRYPOINT commands such as migrate, makemigrations, or loaddata might help a lot, or flags like -d running the docker container allow you to execute extra commands after the docker initialization.

Deployment with GUNICORN & NGINX in EC2

I do not want to talk a lot about nginx and gunicorn right now (I'll do it later in a different post) but integrating it for the production result is vital, and both can be integrated easily (obviously no) in Django.

After installing gunicorn and nginx and dockerazing the project, the way to build the project might be as follows (use the loaddata command in case you need to populate the database). I always recommend (by experience and after not saving a copy of my database) to generate a copy for repopulating the database.

Technologies Used

I have used all these technologies before, and the "why" behind choosing them and using them is because of their reliability and popularity which directly implies support and extra features.

Contributing

Contributions to this project are welcome! If you encounter any issues or have suggestions for improvements, please open an issue or submit a pull request. When contributing, please follow the existing code style and conventions.

License

This project is licensed under the MIT License.

Contact

Thank you for reading me and if you have any questions or feedback, feel free to reach out: