Django School Tool Tutorial
The complete solution code for this tutorial is available here. Also take a look at the complete live site.
We're doing to build a website for a school that allows us to keep track of courses, staff and students. We'll create a page where people can come to the school website and see what's courses are currently being offered. The site will include an administrative interface where webmasters can CRUD (create, read, update, delete) everything in teh system.
Start the Project
Django has a concept of "projects" and "apps." A project is a collection of apps. Django won't let you have a project and an app with the same name. I personally find it a good practice to keep simple projects and apps with generally the same name, with "site" appended to the top-level "project."
Most of my Django work involves projects with only one app.
Project Name: "schooltoolsite"
App Name: "schooltool"
Configure the Project
We have to manually add the schooltool app to the schooltoolsite project.
Edit the file at schooltoolsite/settings.py
. Change INSTALLED_APPS to include a reference to SchooltoolConfig
. You can see SchooltoolConfig
defined inside schooltoolsite/schooltool/apps.py
.
Notice that "tool" in SchooltoolConfig
is not capitalized.
schooltoolsite/settings.py:
Configure the Database and Time Zone
Scroll through schooltoolsite/settings.py
and look for where the database is configured. Django uses a local sqlite database by default. Let's change this to use a local postgresql database.
While we're in settings.py scroll down a bit further to configure the TIME_ZONE
. There's a long list of pre-defined time zones built and maintained by an organization called IANA (Internet Assigned Numbers Authority). They do the hard work of figuring out how real-world messy time zone should be represented inside computers and we can simply refer to one of their official zone names and Django and our database will figure everything out.
The closest official time zone name for Seattle and the West Coast is 'America/Los_Angeles'. Use this.
If you want to nerd out on the entire list of time zones available in this list, and want to know more about the time zone database or IANA then go read up on all these things on Wikipedia. This knowledge isn't really required for any project or job, but it's good to get a sense of who all is out there in the world of programming and how much work it takes to keep things up and running.
Start the Server
Start the server to see if you've made any silly mistakes so far.
Make sure you're in the directory called "schooltoolsite" and run the runserver command:
You'll see something like this:
If you see errors you'll have to track down what's wrong and fix it.
If everything is configured correctly you'll see a website that says, "It worked!" and it will give you advice about what it thinks you should do next.
Customize Layout
Let's carve out some initial template and layout infrastructure. We won't be able to see these pages yet, we'll hook up URL routing next.
Create a folder called
static
in schooltoolCreate a folder called
schooltool
in the newstatic
dir.Create a file called
style.css
instatic/schooltool
Create a folder called
images
instatic/schooltool
Put an image called
background.jpg
in the images folder.
Create a folder
templates
in schooltool and create a folder calledschooltool
inside that.
Create a file called
base.html
inschooltool/templates/schooltool
Create a file called
index.html
inschooltool/templates/schooltool
At the end, you should have all these folders and files:
Pieces of Django Magic
As web developers it's important for us to understand what is doing what. Generally, what we're doing here is writing HTML pages, using CSS to style that HTML, and referencing an image that exists somewhere. Let's break down where the Django magic happens:
The CSS file has no special Django magic. It includes one URL that points to a background image. There's nothing special about this URL. The URL depends on us configuring our static folder how Django expects.
The base.html
file has some Django magic in it. First, notice that the very first line looks like this:
This statement grants the body.html
template access to some special functions that will allow it to refer to files inside the static directory. It uses the static
library that it loaded to attach a href attribute to bring in the CSS.
The base.html
file has one more piece of Django magic called a template block. A template block basically defines where content from other templates will be rendered inside of this template. The template block defines itself with a name, so in the future other templates can fill themselves in in different parts of the page.
Notice that our base.html file defines the basic structure for a classic HTML pagee then usese the content block to define where other template will be rendered inside the page. The index.html file starts out by saying that it extends from the base.html page and it has it's own template block with the same name, "content," surrounding all of the HTML that it will fill in on the base.html page.
Summary of base.html
Summary of index.html
Literal File Contents
Here's what all of your files should look like:
schooltoolsite/schooltool/static/schooltool/style.css
schooltoolsite/schooltool/templates/schooltool/base.html
schooltoolsite/schooltool/templates/schooltool/index.html
Customize URL Routing
Now that we've got static files and a base layout and an index page all configured let's hook up URL routing to tell our server when it should show each of these things.
Add an
index
definition in a fileschooltool/views.py
Create and configure a file called
urls.py
in schooltoolInclude the
schooltool.urls
file inschooltoolsite/urls.py
After you make these files you should be able to run the server and navigate to something like http://localhost:8000 and see the website with a navbar, an h1 and "Welcome to school tool" as defined in the base.html and index.html files.
schooltool/views.py
schooltool/urls.py
schooltoolsite/schooltoolsite/urls.py
Define Models
It's time to decide what we want our site to do. In general we want to have our models look something like this:
Courses have titles, a start and end date, and a max_students property
Staff that have names and can be assigned to teach courses
Students that have names and can sign up to take courses.
Django has pre-defined common field types for different types of data we would want to represent in our model. Here's a small list of model Fields we can use and their mandatory default parameters:
CharField(max_length=200)
TextField
IntegerField()
DateField()
DateTimeField()
EmailField()
See the full list of built-in fields here: https://docs.djangoproject.com/en/1.10/ref/models/fields/
We'll attach a custom __str__
method to each of our models to define how the model should show itself when we render it in our shell, or in the admin interface.
The Django documentation provides excellent examples of how to define and interact with Many-to-One and Many-to-Many relationships:
schooltool/models.py:
Use manage.py to detect, generate and execute database migrations:
Register Models with Admin Interface
Take an extra step to register these models with the Django administrative interface. First, use manage.py to create a super user. A super user is an account that has complete administrative access for everything on the site. Generally you'll want to create one super user account and then configure all other accounts to have only the administrative priveleges they need.
The createsuperuser command will prompt you to enter a username, email address and have you create a password. It's intuitive.
We have to manually register which models we want to make available in the administrative interface. Let's register each of the models we just made.
schooltool/admin.py
Make sure your server is running and navigate to http://localhost:8000/admin to see the beautiful admin tool Django creates for you based on how you defined your models.
The admin tool automatically provides a professional-looking HTML interface where you can do to create new courses, add new students and staff and edit anything inside your database. The fact that Django creates this interface for free based on how you define your models is a huge benfit of using Django!
Try to model courses, students and staff you know are on campus right now:
WDI 11 - Steve, Sean WDI 12 - Brandi, Jackson
Display Courses On the Index
Now that we have views and models defined, let's try to hook them together so we can query our database, get model instances back and display them on the page.
Use python3 manage.py shell
to open an interactive shell where you can practice using Django's built in ORM to query your database for your models. Make sure you have ipython3
installed so you get the most enhanced Python shell possible.
Import Course from schooltool.models. Use the ORM to query for all of the courses. We're using the shell here to make sure we know how to query the model correctly. We'll use what works here in our view to gather data to render in a template.
Change the index
definition in our views file to run this query and send the result of the query as an object to the index template:
schooltool/views.py:
schooltool/templates/index.html:
Create a Page to Display Course Details
Make a new file inside the schooltool/templates/schooltool/ folder called course_details.html
. We'll write HTML that displays the course title and shows lists of the staff and students.
There's one slight gotcha in the Django templates. Don't add parenthesis to function calls. If you want to iterate over the staff of a course write a for loop like this, without parenthesis on the call to .all
:
If you add parenthesis you'll see an error saying:
schooltool/templates/schooltool/course_details.html:
Configure the urls.py in the schooltool folder to have a regular expression that grabs the course_id off the URL and passes it to the details method.
Django has a special regular expression syntax that allows you to name patterns.
( )
parenthesis surround the entire parameter definition and pattern?P<course_id>
identifies the regular expression as a parameter namedcourse_id
[0-9]+
is the regular expression that identifies what acourse_id
lookslike. This regular expression means "match anything comprised of one or more
letters where each letter is a digit from zero through nine.
The rest of the url definition you see is regular regular expression syntax:
r''
means the entire string is a regular expression^
means to match the beginning of a line of stringcourses/
simply defines a mandatory prefix in the URL path$
means to match the end of a line of string
Honestly, these URL pattern definitions are much easier in Express. In express we would simply write:
Don't let the syntax get you down. Transcend the syntax!!
Make a small change in the index.html template to wrap course titles in anchor tags leading to the course detail page:
Now the homepage displays a list of courses with links to the course detail page for each course. The course detail page shows the course title and shows who's teaching and who's enrolled in the course as a student.
Add a Form to Allow Students to Enroll
Add a form to the course_detail.html page that accepts a students name. Hook up the form so it POSTs it's information to /courses/course_id/
.
Rewrite the details method so it detects when a POST request occurs. Peel the "name" value out of the body of the POST request. Create a new students and set their name to the value of the name in the POST request, and set their course as the course that is associated with the course_id
.
Now students can navigate to one course and enter their name to sign up for the course.
I also added some logic to the template to show the current capacity of the course. It counts up the number of students enrolled and prints out the number of max_students in the course too.
Last updated