Setting Up My Environment
To start developing my Django application, I need to have Python installed on my system. If it's not installed yet, I can download it from the official website here.
Once Python is installed, I can proceed to install Django. It's recommended to use a virtual environment to avoid conflicts with other projects. I will use virtualenv. To install virtualenv, I use the following command:
After installing virtualenv, I create a new virtual environment with the following command:
This creates a new folder named venv in the current directory. To activate the virtual
environment, I use this command:
Once the virtual environment is activated, I see the name of the environment in the terminal. Now I can install Django using pip:
Setting Up My Django Project
After creating my new virtual environment, I navigate to the folder where I want to store the application. I use the following command to start a new Django project:
Django creates a folder with the specified PROJECT_NAME. For this example,
I create a simple CRUD (Create, Read, Update, Delete) application for products named crud_products.
The created folder structure looks like this:
Now, I change the working directory to the folder created by Django, then test if Django is working correctly by running:
(venv) diego@diego-romero.xyz:~/blog/django-scartch-to-deploy$ cd crud_products
(venv) diego@diego-romero.xyz:~/blog/django-scartch-to-deploy/crud_products$ python manage.py runserver
I should see a result like this:
Creating My Application
Now that I have my project set up, I create my first application using the following command:
This creates a new folder named products inside the crud_products folder. The folder
structure now looks like this:
Explaining the Folder Structure
The crud_products folder is the main folder of my project. It contains the settings, URLs, and other
configurations for my project. The products folder is the application I just created. It contains
the models, views, and other components of my application.
Inside the models.py file, I add the database entities that I need to use in my application. In my case, I only create one model called Product.
Inside the views.py file, I add the logic for my application. This is where I define the behavior of my application.
Inside the urls.py file, I define the URLs for my application. This is where I define the routes for my application.
I also need to create a file called forms.py and one called urls.py that will contain the forms and urls for my application respectively.
This is how my models.py looks like:
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
I create a new model called Product with three fields: name, description, and price. The __str__ method returns the name of the product when printed.
This is how my forms.py looks like:
from django import forms
from .models import Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('name', 'description', 'price',)
I define a form for my Product model using Django's ModelForm to create a form for creating and updating products.
This is how my views.py looks like:
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Product
from .forms import ProductForm
class ProductListView(ListView):
model = Product
template_name = 'products/list.html'
class ProductDetailView(DetailView):
model = Product
template_name = 'products/detail.html'
class CreateProductView(CreateView):
model = Product
form_class = ProductForm
template_name = 'products/edit.html'
success_url = reverse_lazy('product_list')
class UpdateProductView(UpdateView):
model = Product
form_class = ProductForm
template_name = 'products/edit.html'
success_url = reverse_lazy('product_list')
class DeleteProductView(DeleteView):
model = Product
template_name = 'products/confirm_delete.html'
success_url = reverse_lazy('product_list')
I define views for my application using Django's generic views to create a list view, detail view, create view, update view, and delete view. I also use a ProductForm to create and update products.
This is how my urls.py looks like:
from django.urls import path
from .views import ProductListView, ProductDetailView, CreateProductView, UpdateProductView, DeleteProductView
urlpatterns = [
path('', ProductListView.as_view(), name='product_list'),
path('product//', ProductDetailView.as_view(), name='product_detail'),
path('product/new/', CreateProductView.as_view(), name='new_product'),
path('product//edit/', UpdateProductView.as_view(), name='edit_product'),
path('product//delete/', DeleteProductView.as_view(), name='delete_product'),
]
I define the URLs for my application using Django's path function to define routes.
Now, I add my application to the INSTALLED_APPS list in the settings.py file.
This is how the INSTALLED_APPS list looks like:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Local apps
'products',
]
Now I run the migrations to create the database tables for my application with the following commands:
(venv) diego-romero.xyz:~/blog/django-scartch-to-deploy/crud_products$ python manage.py makemigrations
(venv) diego-romero.xyz:~/blog/django-scartch-to-deploy/crud_products$ python manage.py migrate
After running the migrations, I see output like this:
Migrations
Migrate
Now my application is ready, but I can't access it yet. I need to create the templates for my application. I start by setting the templates configuration in the settings.py file.
import os #Add this import
## Rest of the code
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
This allows me to use a templates folder to store templates. Now I create the templates folder in the root folder of my project and then create a base.html inside this directory where I define the structure of the page.
This is how my base.html looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Django App{% endblock title %}</title>
<!-- Additional CSS files or external stylesheets can be linked here -->
</head>
<body>
<header>
<nav>
<!-- Navigation menu -->
<ul>
</ul>
</nav>
</header>
<main>
{% block content %}
<!-- Content will be overridden in child templates -->
{% endblock content %}
</main>
<footer>
<p>© 2024 My Django App. All rights reserved.</p>
</footer>
<!-- Additional JavaScript files or external scripts can be included here -->
</body>
</html>
Now I create the templates for my application. I create a folder called templates inside my application's folder, where I create files for my views.
- list.html
- detail.html
- edit.html
- confirm_delete.html
This is how my list.html looks like:
<!-- templates/products/list.html -->
{% extends 'base.html' %}
{% block title %}Product List{% endblock %}
{% block content %}
<h2>Product List</h2>
<a href="{% url 'new_product' %}">Add New Product</a>
<ul>
{% for product in object_list %}
<li>
{{ product.name }} - {{ product.price }}
<a href="{% url 'product_detail' product.pk %}">View</a> |
<a href="{% url 'edit_product' product.pk %}">Edit</a> |
<a href="{% url 'delete_product' product.pk %}">Delete</a>
</li>
{% empty %}
<li>No products available.</li>
{% endfor %}
</ul>
{% endblock content %}
This is how my detail.html looks like:
<!-- templates/products/detail.html -->
{% extends 'base.html' %}
{% block title %}Product Detail{% endblock %}
{% block content %}
<h2>{{ product.name }}</h2>
<p>Description: {{ product.description }}</p>
<p>Price: {{ product.price }}</p>
<a href="{% url 'edit_product' product.pk %}">Edit</a> |
<a href="{% url 'delete_product' product.pk %}">Delete</a> |
<a href="{% url 'product_list' %}">Back to list</a>
{% endblock content %}
The other templates are similar in structure, with specific content for each action (create, update, delete).
Finally, I add my application's URL configuration to the project's URL configuration. I open the urls.py file in the project's folder and include the URLs from my application.
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('products/', include('products.urls')),
]
Now, my application is fully configured and ready to use.
I can access to the application going to localhost:8000/
This is how my application look like:
List
Create
List after create
Detail
Edit
Delete
Deploying My Django App Using Apache 2
Setting Up Apache and mod_wsgi
To deploy my Django application using Apache 2, I first need to install Apache and mod_wsgi, an Apache module for hosting Python web applications.
Install Apache:
Install mod_wsgi:
For Python 3 applications, use:
Enable the module if it's not automatically activated:
Configuring Apache to Serve the Django Application
Prepare the Django Application:
Set DEBUG = False in Django settings.
Configure ALLOWED_HOSTS with domain names/IP addresses.
Collect Static Files:
sudo nano /etc/apache2/sites-available/myapp.conf
Add the configuration, adjusting paths as needed:
<VirtualHost *:80>
ServerName mydomain.com
ServerAdmin webmaster@localhost
Alias /static /path/to/myapp/static
<Directory /path/to/myapp/static>
Require all granted
</Directory>
Alias /media /path/to/myapp/media
<Directory /path/to/myapp/media>
Require all granted
</Directory>
WSGIDaemonProcess myapp python-path=/path/to/myapp python-home=/path/to/venv
WSGIProcessGroup myapp
WSGIScriptAlias / /path/to/myapp/myapp/wsgi.py
<Directory /path/to/myapp/myapp>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Enable the virtual host:
diego@diego-romero.xyz:/etc/apache2/sites-available$ sudo a2ensite myapp
diego@diego-romero.xyz:/etc/apache2/sites-available$ sudo a2dissite 000-default
Restart apache:
Final steps
- After restarting Apache, my Django application should be live at the specified
ServerName. - Test the application by visiting
http://mydomain.comin a web browser.






Comments
Post a Comment