Tuesday, April 16, 2024
Django Website with Tailwind CSS, Bootstrap, JavaScript, and GSAP
Harrinson Arrubla
@ TwitterWelcome 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
- Setup
- Usage
- Sitemaps
- Dockerization
- Deployment with GUNICORN & NGINX in EC2
- Technologies Used
- Contributing
- License
- Contact
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
- 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
- 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
- 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.
- Django (Python web framework)
- Tailwind CSS (CSS utility framework)
- Bootstrap (CSS framework)
- JavaScript
- GSAP (JavaScript animation library)
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:
- Email: [email protected]
- Twitter: @haarrublar