Django is a Python framework that I’ve written about before. I’ve compared Django to ASP.NET MVC. But, I didn’t go into much detail about how to actually use Django to create a data driven website. That’s what I’ll cover now.
The goal for this ‘Getting Started’ project is to get familiar with the basics of developing data driven web applications using Django, Models, Views, Templates, URLs, and Forms. By the end we’ll have a simple contact form that saves user submissions to the database, and displays that data to an administrator user. It will not be a completed site, but it will introduce basic the building blocks of website development in Django.
If you’d like to refer to the end goal of this article, you can find it on GitHub.
Prerequisites
- Windows 10
- Or your own favorite OS. But I’ll be writing from a Windows perspective.
- Python 3.6 or above.
- VS Code with Microsoft’s Python extension installed.
- Or your own favorite Python IDE/editor, but I’ll be writing from the VS Code perspective
Create Project
Make the project directory and navigate inside.
> mkdir django-project && cd django-project
Create a Virtual Environment to isolate project specific dependencies.
> python -m venv django-env
Activate the venv. (This is the Windows command.)
> django-env\Scripts\activate.bat
Note: Once inside an activated venv, you can leave it to work on other things by using the
deactivate
command.
Install Django inside the active venv. (You don’t want to install packages globally. Make sure that the venv is active.)
(django-env)> pip install django
Use django-admin
to create the new Django application.
(django-env)> django-admin startproject djangosite
That created a new folder called djangosite
and it placed boilerplate files inside. manage.py
is one of those files and it’s what will used from now on to run Django commands.
Run the development Django server from inside the site’s folder.
(django-env)> cd djangosite
(django-env)> python manage.py runserver
Visit localhost:8000 to verify that it’s working. Then exit the server with Ctrl+Break.
When the Django server ran, Django automatically created a db.sqlite3 file in the project folder. Read more about configuring different database backends.
Use VS Code to open the django-project
folder that houses the virtual environment folder and the Django app folder. This can be done from the terminal, or manually inside VS Code.
> code ..\.
Open djangosite\urls.py
. The imports for Django will probably be shown as missing modules because Django was installed in the venv and not globally. to fix this, press ctrl+shift+p
then execute the command Python: Select Interpretter
. Find .\django-env\Scripts\python.exe
from the list and select it. Then VS Code will stop showing the Django imports as errors.
For more VS Code information visit Getting Started with Python in VS Code.
Add a Custom Django View
To add a ‘Hello World’ page, create a new file in django-project\djangosite\djangosite
called views.py
. Add the following code.
from django.http import HttpResponse
def welcome(request):
return HttpResponse("Hello, World!")
To tell Django when to execute this welcome view, edit urls.py
so it looks like this:
from django.contrib import admin
from django.urls import path, re_path
from .views import welcome
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^$', welcome)
]
Browse to localhost:8000 and see the custom message.
Let’s take a quick break to go over some Django concepts.
App
A Django App is a python package that acts as a little web application of its own. With it’s own Models, Views, Templates, and URLs. Most Django sites use several apps. It is also possible to write an app such that it can be reused in other Django projects.
Model
A Django Model is a data model that maps to a database table. This introduces the concept of Migrations.
Migrations
The model will usually change as the site is developed. A migration will update the corresponding database table from previous versions to the new version of the code. As migrations get more complicated, there may be need to write custom migration scripts.
Views
Views in Django are like Controllers in ASP.NET MVC. They are what connect a model with a template.
Templates
Templates in Django are like Views in ASP.NET MVC. They are the display layer; the HTML that will render in the browser.
Add a Custom Django Model
Show migrations
(django-env)> python manage.py showmigrations
Execute those migrations
(django-env)> python manage.py migrate
Now create a new Django app. For this example, it will handle the functionality for a contact form.
(django-env)> python manage.py startapp contactform
Move into the new contactform
directory and notice that Django has created a bunch of boilerplate code for us.
(django-env)> cd contactform
(django-env)> dir
Add this new app to the Django site. Open settings.py
in the djangosite
folder, and add the contactform
app to the list of installed apps. INSTALLED_APPS
should look like this:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'contactform'
]
Then, open the models.py
file in the contact form app and add the class that will represent the contact form.
from django.db import models
class ContactForm(models.Model):
HOW_DID_YOU_HEAR_ABOUT_US_CHOICES = (
('SE', 'Search Engine'),
('Q', 'Quakkels.com'),
('F', 'From a friend'),
('O', 'Other')
)
name = models.CharField(max_length=50)
email = models.EmailField(max_length=50)
comments = models.CharField(max_length=500)
how_did_you_hear_about_us = models.CharField(max_length=2, choices=HOW_DID_YOU_HEAR_ABOUT_US_CHOICES)
More information about Django models can be found here.
After the model is saved, create the new migration script.
(django-env)> python manage.py makemigrations
Run the migration.
(django-env)> python manage.py migrate
If you’re curious about what the SQLite database tables look like, you can download something like DB Browser for SQLite. Table names will be named after the model with the app name as the prefix. So the table for ContactForm will be called
contactform_contactform
.
Register Custom Model in Admin
To make contact form submissions available to be read by a site administrator, ContactForm
needs to be registered in the admin area.
Open contactform\admin.py
and add this code to register the ContactForm model.
from django.contrib import admin
from .models import ContactForm
@admin.register(ContactForm)
class ContactFormAdmin(admin.ModelAdmin):
list_display = ('name', 'email')
Create a super user for logging into the site’s admin area.
(django-env)> python manage.py createsuperuser
Now when the development server runs, you’ll be able to view and edit ContactForms in the Admin area by navigating to localhost:8000/admin and using the new super user to log in.
Create a Custom Django Template
Double check the terminal’s working directory is the contactform
folder inside of djangosite
.
(django-env)> pwd
Switch to contactform
if it’s not the working directory.
Create a new folder for custom templates.
(django-env)> mdkir templates
In VS Code, create a file in the new templates folder called contactform.html
for the contact form. Put the following code in the file for now.
<!DOCTYPE html>
<html>
<head>
<title>Contact Form</title>
</head>
<body>
<h1>Contact Form</h1>
</body>
</html>
Next, update contactform\views.py
with this code.
from django.shortcuts import render
def contactform(request):
return render(request, "contactform.html")
Notice that the render()
function is used here instead of returning HttpResponse()
directly like the “Hello, World!” view does. The render()
function will use the template for the html.
To make the template visible from the browser, we need to route requests to the view based on the URL.
Use VS Code to create a urls.py
file inside the contactform
folder. Put this code inside it.
from django.urls import re_path
from .views import contactform
urlpatterns = [
re_path('contactform$', contactform)
]
The re_path()
method uses a string as a regular expression. The 'contactform$'
ensures that it only matches on paths that end in contactform
.
Since djangosite\urls.py
is what Django uses to route urls, it needs to be aware of the new contactform\urls.py
. Update it with this code.
from django.contrib import admin
from django.urls import path, re_path, include
from .views import welcome
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^contactform/', include('contactform.urls')),
path('', welcome),
]
'^contactform/'
is a regular expression that makes sure matching paths begin with contactform
. This is a prefix for everything in the contactform app. So the complete matching path will be localhost:8000/contactform/contactform
. For more information read the Django documentation.
Create a Form
Create a new file in contactform
called forms.py
and put this code in it.
from django.forms import ModelForm
from .models import ContactForm
class ContactFormForm(ModelForm):
class Meta:
model = ContactForm
fields = ('name', 'email', 'comments', 'how_did_you_hear_about_us')
It was at this time that I started regretting how the
ContactForm
model was named. To stick with Django conventions, this form class will be the name of the model with “Form” appended to it. Hence;ContactFormForm
. Future me will not make this mistake.
Update contactform\views.py
so it will send the new form class as an object to the template.
from django.shortcuts import render
from django.http import HttpResponse
from .forms import ContactFormForm
from .models import ContactForm
def contactform(request):
form = ContactFormForm()
context = {
'form' : form,
}
return render(request, "contactform.html", context)
Update the contactform.html
template to use the form
object in the context
.
<!DOCTYPE html>
<html>
<head>
<title>Contact Form</title>
</head>
<body>
<h1>Contact Form</h1>
<form method="POST">
{% csrf_token %} <!--this token is required in order to prevent CSRF attacks-->
{{ form }} <!-- the form object will render our FormModel -->
<button type="submit">Send</button>
</form>
</body>
</html>
You can find more details about how to properly use templates here. The code above has much room for improvement.
Two things worth noting here are {% csrf_token %}
and {{ form }}
. The code for CSRF Token prevents this page from being vulnerable to cross site request forgery attacks. The form
object is the ContactFrom
model converted to HTML form elements via the ModelForm
class.
Update the view to accept and save a Contact Form submission.
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import ContactFormForm
from .models import ContactForm
def contactform(request):
form = ContactFormForm()
context = { "form" : form }
if request.method != "POST":
return render(request, "contactform.html", context)
form = ContactFormForm(data=request.POST)
if not form.is_valid():
context["form"] = form
return render(request, "contactform.html", context)
form.save()
return redirect("/")
This will render the form on first request. When the form is submitted it will check the values against what the model expects. If the values aren’t valid it will render the form again (ideally to inform the user there were problems and give them a chance to correct mistakes.) If the values are valid, then it will save a new record in the database which an admin will be able to see in Django’s administration section. Once the record is saved, the user gets redirected to the site root.
Summary
There’s a lot more to Django, but this is a fair amount of information to get started with it. What we wrote has an authenticated admin area, a ‘hello’ home page, and a data driven form that persists data to a database. This isn’t a completed web application, but we did cover a lot of essential building blocks.
Resources
Please share this post with a friend, and subscribe to get notified of new posts.
Comments may be sent to blog@quakkels.com.