This project covers how to build a web application using Django. Django is a high-level Python web framework that encourages rapid development. It is free and open source.
Django was designed to:
For more background information on Django, visit: https://www.djangoproject.com/
We will be working through Chapters 18 through 20. Chapters 18 and 19 focus on creating and fine tuning a web app. Chapter 20 deals with styling the app using Bootstrap 4.0 and deploying the app to Heroku.
In chapter 18, we will be using the command prompt to configure the virtual environment, install Django and execute commands to run the app. We will use a web browser to view the running app and enter data AND we will enter Python code for the models and views using VSCode.
Tasks covered in chapter 18 include:
We will be working through the chapter to create a Learning Log application AND a Pizzeria application. The Learning Log instructions are in the chapter text itself and the Pizzeria application we will create by completing the Try-it-Yourself exercises.
The lecture video is combined with the hands on video. Each hands on exercise has a separate video :)
A project specification is a detailed description of objectives for any given development project. It lists goals, functionality, and any other information that is required for the developers to successfully complete the project.
Project specifications have been around for a long time (we had them when I was a programmer!) Details project specs include:

For our Learning Log project, our specification is a simiplified version of one you would find in industry
For server-side applications, you work in a virtual environment. To set up our environment, we need to:
1) Create a directory for our learning logs application
2) Use the command prompt, navigate to our directory and create a virtual environment
3) Activate the virtual environment
4) Install Django
You need to create a folder on your system where you plan on running the application from
Example:
1. Open the command prompt and navigate to the directory.
Example: At the prompt, I entered cd documents/CIT228/learning_log as shown below:
After you execute the command you should notice the "path" has changed and includes your directory.
2. Create a virtual environment in your directory
Syntax: python -m venv environment_name
Where environment name is what you are calling your virtual environment (you will use this name to activate the environment anytime you want to run your app locally)
Example: At the prompt, I entered python -m venv ll_env (ll_env is short for learning log environment)
NOTE: After you enter the command, you will see the prompt display (there is no additional code that shows up)
Behind the scenes, inside your learning_log directory, you will see several directories and files that have been created
Anytime you want to run your app locally, you will need to activate your virtual environment.
To activate your session, change directories to the Scripts directory and then type activate. As you can see in the directory structure above, the Scripts folder is inside the ll_env folder. It contains the activate script that needs to run.
Example:
cd ll_env/Scripts
activate
When you are done working on your app, you should deactivate the virtual environment.
To deactivate the virtual environment, simply enter deactivate at the prompt or close the command prompt window.
Example
From inside the active, virtual environment, you need to install Django. Once it is installed, it will only be available to you when you are working inside this environment
Syntax: pip install django
Example:
If you are working on multiple projects, each one will have it's own virtual environment with Django installed.
To see a video demonstration and explanation, view: https://youtu.be/qUiOqKir24w
1. Create the learning_log directory inside your CIT228 folder (this should be done outside VSCode, just use the Windows File Explorer)
2. Open the command prompt or powershell and navigate to your learning_log directory.
3. Create the virtual environment by entering:
python -m venv ll_env
Look inside the learning_log directory you created to see the directory structure. You will need to activate the virtual environment by running the activate command which is inside the Scripts directory
3. Activate the environment
MODIFICATION TO TEXTBOOK DIRECTIONS: To get the command to work, I had to change directories to the Scripts directory and from there, I could run the activate command
To change directories, I entered: cd ll_env/Scripts
To activate the virtual environment, I entered: activate
Example:
NOTE: Once the environment is active, you will see (ll_env) before the prompt
4. From inside the virtual environment, install Django
To install, enter: pip install django
Example:
5. Keep the command prompt window open with the virtual environment active.
Projects need to be created inside the virtual environment. You should see the name of your environment in parenthesis before the prompt in the command prompt window.
Make sure the directory you are creating the project in is your main project directory (you may need to navigate back to that directory if you are in the Scripts subdirectory).
Syntax to go up 1 level: cd ..
cd is for change directory
two dots means go up 1 level
Syntax to create project files: django-admin startproject directory .
Example: django-admin startproject learning_log .
IMPORTANT: The dot at the end creates the new project with a directory structure (don't forget to enter it!)
Example navigating up 2 levels and creating the project files in the main directory:
Syntax to view files within the current directory: dir
NOTE: In the book they use ls; however, on a Windows system, you will need to use dir which is short for directory
Example:
How to read the directory listing:
Syntax to view files within a subdirectory: dir subdirectoryName
Example: dir learning_log
Learning log includes 3 python files that are important for our project:
To see a video demonstration and explanation, view: https://youtu.be/v5WKPtelyHU
1. Navigate to the learning_log directory and make sure the virtual environment is active (you will probably need to type cd .. two times to get back to the learning_log directory)
2. Create the project inside the learning_log directory
IMPORTANT: Make sure you include the dot at the end - you will have problems deploying the app if you forget it. Your command should be: django-admin startproject learning_log .
Example: The example shows entering cd .. two times followed by the command to create the project in the learning_log directory
3. View files created
a) Type dir at the prompt to see the files and directories in learning_log
b) Type dir learning_log to see the files and directories inside
(View the information above for an explanation of what the directories contain)
Running the migrate command will update an existing database with modifications AND it will create a new database if it doesn't exist.
Django uses SQLite which is a version of SQL that runs off a single file and works well for simple apps. It involves minimal database management. For more information on SQLite, see: https://www.sqlite.org/index.html
Syntax: python manage.py migrate
NOTE: python refers to the version you are using, so you can enter the full command without modifying it for different versions
Example: After executing the command, you will see information indicating Django is creating a database with authentication for us.
After the command is done executing, typing the dir command will display a new file: db.sqlite3
Example:
After you execute the migrations to create the database, you can run the app to make sure everything, so far, has been created properly.
Syntax: python manage.py runserver
You will see output indicating it is performing system checks and that it is starting the development server at a URL.
To view the running app, launch your web browser and enter the URL displayed in the command prompt window http://127.0.0.1:8000 OR you can enter localhost:8000
Example of browser window:
Example of additional output in the command prompt window:
To stop the server from running, type CTL + C in the command prompt window.
To see a video demonstration and explanation, view: https://youtu.be/fI0dHaribaY
1. Make sure the learning_log directory is active AND that the virtual environment is active.
2. Enter python manage.py migrate at the prompt
3. To test the app, enter python manage.py runserver at the prompt
4. Open your web browser and enter http://127.0.0.1:8000 or localhost:8000
PROBLEMS: It is using port 8000 to display the app. Sometimes there are port conflicts depending upon what you are running on your system and what you have installed. If you get a port error, you can specify a different port in the runserver command: Example: python manage.py runserver 8001 If 8001 is used, try 8002 etc. unti. you find an open port
If you feel like you need additional practice creating projects, complete Try-It-Yourself 18-1 on page 384 You will not need to turn in anything from this exercise, it is for your own benefit :)
Django is made up of apps that work together to create the project.
As you work on applications, you will want to view them in the browser, so you should keep the browser running and keep the command prompt window associated with the browser open.
When you have the app running in the browser, you should open another command prompt window if you need to execute other commands.
To create the infrastructure needed to build the app, use the following syntax:
Syntax: python manage.py startapp directory_name
Example: python manage.py startapp learning_logs
NOTE: This command creates a new directory and places files in it. In our project, the current directory is learning_log. The name of the new directory should be different from your current directory name which is why it is pluralized with an s on the end.
The startapp command creates several files which you can view by entering the dir learning_logs command
Important files created by startpp include:
To see a video demonstration and explanation, view: https://youtu.be/bMYmahSQV9M
1. With the current app running in the browser, open another command prompt window and navigate to the learning_log directory
Example:
cd documents/CIT228/learning_log
2. Navigate to the Script directory inside learning_log and run the activate command. Then, navigate back to the learning_log directory
Example:
cd ll_env/Scripts
activate
cd ..
cd ..
3. Run the startapp learning_logs command to create the infrastructure needed for the project
Example: python manage.py startapp learning_logs (NOTE the command is learning_logs with an s at the end so a folder will be created that is separate from the existing learning_log folder)
To see what is inside the new folder, enter dir learning_logs at the prompt
You should note the models.py, views.py and admin.py files. For those of you familiar with MVVM and MVC, models will be used for data, views is what the users will see and admin will be for administering the site.
The models.py file imports models from django.db and provides space for user-defined models.
A model is simply a class that specifies the data we will store in the SQLite database
Data classes are inherited from Models
Syntax:
from django.db import models
class ClassName(models.Model):
fieldName1 = models.fieldtype(options)
fieldName1 = models.fieldtype(options)
fieldNamen = models.fieldtype(options)
def __str__(self):
"""returns a string representation of the model"""
return self.text
To see a list of field types and field options, see: https://docs.djangoproject.com/en/2.2/ref/models/fields/
VSCode Example:
Once you have defined models, you need to include them in the application. This is done in the settings.py file. Our app needs to be included in the INSTALLED_APPS section
You should put your apps above the default, django apps in case there are settings you need to override. It is also a good idea to include comments so others know which are the django apps and which are the apps you added to the project
VSCode Example:
Everytime you make a change to a model, you need to run migrations to modify the corresponding database
This is done back in the command prompt (make sure you are in the virtual environment)
This is a two step process:
Syntax: python manage.py makemigrations learning_logs
NOTE: learning_logs represents the directory where the models.py file is located. That is what we need to create migrations for.
Look closely at the output - if you see a traceback and error message, the command didn't work because there is a problem in your model.py file. You wll need to fix the problem and run the command again.
Example of a command that worked:
Example of a command that did NOT work (there was an error in DateTimeField, it was keyed in as DateTimefield (lowercase f)
If you successfully ran the makemigrations command, Django will use the models.py file to create a new file containing instructions for a new or revised table. At this point, you can apply the migration using the migrate command.
Syntax: python manage.py migrate
After you execute the migrate command, Django will apply the migration file and update your database.
The first line in the output is the most critical because it indicates if the migration worked (it should indicate it was OK)
Example:
The code in the models.py file represents classes that will become tables in the database.
Anytime you add or revise a class in that file, you need to do the following:
1. Open the command prompt and navigate to your directory
2. Activate the virtual environment
3. Run the makemigration command and make sure it is successful
4. Run the migration command to apply the changes to your database
To see a video demonstration and explanation, view: https://youtu.be/otuCsKVYocs
1. Go into VSCode and open make the learning_log directory your active folder.
2. Open learning_logs/models.py and make the changes on page 385 (be careful, the fieldtypes are case sensitive). You will be creating a Topic class that will become a table in your database.
3. Save your changes
4. Open learning_log/settings.py and add the learning_logs directory to INSTALLED_APPS as directed on page 386.
5. Save your changes.
6. Go into the command prompt and make sure the Learning_Log directory is the current directory and your virtual environment is active
7. Run the makemigration command to create the file Django will use to update the database
python manage.py makemigrations learning_logs
8. Make sure the command worked - if you see traceback errors, it did not work. Look at the output to determine what the problem is (normally it is a typo)
9. After the makemigrations command is successful, apply the migration using the migration command
python manage.py migrate
Django allows you to work with your models through the admin site in your web browser.
To use the admin site, you need to create a superuser account(in many operating systems, the superuser is the name given to the administrator)
A superuser can do anything at the site (they have all the privileges to read, write and execute).
Users of a site can be given different privleges that can restrict what they are allowed to do. Registered users are normally allowed to read and edit their own posts.
Normally, only the administrator (or superuser) has priveleges to access everything.
To create a superuser, enter the following command at the command prompt (make sure you are in the correct directory and that the virtual environment is active)
python manage.py createsuperuser
Answer the prompts the system gives you to create the username and password.
NOTE: Django doesn't store the password in human readable form. It stores a hash instead. A hashed password is a scrambled version of the password that uses a key from the site in addition to jumbled values from the password itself. There are algorithms a site uses to determine how to create the password and how to access it. Each time you enter your password, Django hashes it and compares it to the hashed version it has stored. The two must match for you to access the system.
To see a video demonstration and explanation, view:
1. Go into the command prompt and make sure the Learning_Log directory is the current directory and your virtual environment is active
2. Run the superuser command and answer the prompts (make sure you choose things you can remember)
python manage.py createsuperuser
Example:
NOTE: The first time my password was too easy and it rejected it, so I had to enter a more difficult one
To access a model as an administrator, you need to register it with the admin site. This is done in the admin.py file.
You need to open learning_logs/admin.py in VSCode and add code to import your class and register it
Syntax:
from .models import ClassName
admin.site.register(ClassName)
Example:
NOTE:
1) the dot in front of models in the import statement tells Django to look for the models.py file in the same directory as the admin.py file
2) the admin.site.register command tells Django to manage our model through the admin site
After you have created the superuser account AND registered your models, you can access them through the admin site in the web browser.
To do this, your site has to be running. If it it isn't running, you need to go into the command prompt and execute the python manage.py runserver command. Then, you need to launch the web browser and enter: http://localhost:8000/admin/
If the app is already running, all you need to do is edit the address and add /admin/ to the end.
The app will reroute you to a login screen where you need to enter your username and password
After you login, you should see the admin panel
From this page, you can enter new users, groups and you can add, view and edit topics.
To see a video demonstration and explanation, view:https://youtu.be/bmYHXfLULBQ
1. Open learning_logs/admin.py in VSCode and add the code on page 388 to import your class and register it
2. Make sure your app is running in the web browser and type localhost:8000/admin in the address bar and press enter.
3. You should see the login prompt. Enter the superuser username and password you created in hands on #7
4. To add a new topic, click the Add link in the Topics section. Enter Chess as a topic and save it. Enter Rock Climbing as a topic and save it. Add any additional topics you would like.
Models become tables in your database. After creating the first model, you will create additional models which will become tables when you execute migrations.
Each model you create will be a class in the models.py file
To connect our models so the tables can share data, we will specify foreign keys, in addition to field types.
Django allows many-to-one, one-to-one and many-to-many relationships. Because a many-to-many relationship is a problem in a database, Django creates an intermediary join table behind the scenes to represent the many-to-many relationship and it maintains the table for you.
In Django, many-to-one relationships are defined using a ForeignKey (https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_one/)
Example (retrieved from docs.django.com, March 2021):
from django.db import models
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self):
return self.headline
class Meta:
ordering = ['headline']
One-to-one relationships are defined using a OneToOneField (https://docs.djangoproject.com/en/3.1/topics/db/examples/one_to_one/)
Example (retrieved from docs.djangoproject.com, March 2021 ):
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self):
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self):
return "%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return "%s the waiter at %s" % (self.name, self.restaurant)
Many-to-many relationships are defined using a ManyToManyField (https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/)
Example (retrieved from docs.djangoproject.com, March 2021 ):
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
Example with 3 classes (i.e. 3 tables). NOTE the many-to-one relationship between Blog and Entry and the many-to-many relationship between Author and Entry.
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
def __str__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
number_of_comments = models.IntegerField()
number_of_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
A majority of the relationships you create will be many-to-one.
Syntax:
from django.db import models
class ClassName1(models.Model):
fieldName1 = models.fieldtype(options)
fieldName2 = models.fieldtype(options)
fieldNamen = models.fieldtype(options)
class ClassName2(models.Model):
lowercase_classname1 = models.ForeignKey(ClassName1, options)
fieldNamen = models.fieldtype(options)
where options for the foreign key include on_delete=models.CASCADE
The on_delete option tells Django to remove related rows in ClassName2, if an entry from ClassName1 is deleted.
Example from the book:
In this example, on_delete will remove entries for a topic if that topic is deleted. You will note the naming convention for the field is to enter the class you are connecting to in all lowercase letters. In the options for models.ForeignKey, you provide the class name you are connecting to and the on_delete option.
Meta classes let you customize the database in a variety of ways.
Example:
from django.db import models
class Customer(models.Model):
age = models.IntegerField()
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(age__gte=18), name='age_gte_18'),
]
Example of plural names
In a class named Story, stories would be used for multiple entries. If you don't specify a plural name, Django will just add an s to the end of the existing name (i.e. storys)
Example of human readable names
If you don't provide a verbose_name, deptName will become dept name (you will lose the camelcasing)
For additional meta options, see https://docs.djangoproject.com/en/3.1/ref/models/options/
Most classes will include string methods that tell Django how to display longer string entries
Example:
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.CharField(max_length=50)
def __str__(self):
return '{} by {}'.format(self.name, self.author)
After you create a new model, you need to register the model in admin.py
To register the model, you need to:
1. import the class
2. enter the admin.site.register(ClassName) command
Example showing how to add the Entry class
To see a video demonstration and explanation, view: https://youtu.be/_S2DNDOBam4
1. Open learning_logs/model.py in VSCode and add the code on page 390 to create the Entry class and the foreign key to the Topic class.
2. Save your changes.
3. Open learning_logs/admin.py in VSCode and add the code on page 391 to register the new class
4. Save your changes
5. Go into the command prompt and make sure the Learning_Log directory is the current directory and your virtual environment is active
6. Run the makemigration command to create the file Django will use to update the database
python manage.py makemigrations learning_logs
7. Make sure the command worked - if you see traceback errors, it did not work. Look at the output to determine what the problem is (normally it is a typo)
8. After the makemigrations command is successful, apply the migration using the migration command
python manage.py migrate
9. Make sure your app is running in the web browser and type localhost:8000/admin in the address bar and press enter.
10. You should see the login prompt. Enter your superuser username and password you created in hands on #7
Example showing the migration commands and running the server:
Example of what you should see in the browser's admin window:
11. To add an entry for the Chess topic, do the following:
a) Click Entries
b) Click Add Entry
c) Select Chess from the drop down list
d) Make an entry similar to the example below:
"The opening is the first part of the game, roughly the first ten moves or so. In the opening, it’s a good idea to do three things—bring out your bishops and knights, try to control the center of the board, and castle your king."
e) Save your entry (when you return to the "select entry..." screen, you will see the first 50 characters of the entry display because that is what we told it to do in the string method.
f) Select the Add Entry button
and then select the Chess topic from the drop down
g) Make a second entry similar to the example below:
"In the opening phase of the game, it’s important to bring out your bishops and knights. These pieces are powerful and maneuverable enough to play a significant role in the beginning moves of a game."
h) Save the entry
i) Select the Add Entry button and then select the Rock Climbing topic from the drop down
j) Make an entry similar to the example below:
"One of the most important concepts in climbing is to keep your weight on your feet as much as possible. There’s a myth that climbers can hang all day on their arms. In reality, good climbers have practiced specific ways of keeping their weight over their feet whenever possible."
k) Save the entry
At this point, your screen should look like the example below:
Once you have created and populated your classes (i.e. tables) with data, you can use the Django command shell to execute queries. We will focus on retrieval queries, although you could also execute update queries. To see a full list of queries, view: https://docs.djangoproject.com/en/2.2/topics/db/queries/
Syntax: python manage.py shell
NOTE: you need to be in the virtual environment and in the directory where you installed Django
After executing the command, you will see 3 angle brackets as a prompt. You can enter queries at the prompt (or code) you want executed.
To exit the shell, type >>> exit()
You can double check your queries using the shell to make sure it retrieves the data the way you want it to. (You will use similar queries in your view functions to retrieve data to display in web pages.)
A queryset are instances of a model (basically rows withn a table)
To retrieve objects created within a table, you need to import the class used to create the table and then execute the className.objects.all() command
Example #1:
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
The output displayed is the queryset:
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>
Example #2:
>>> from learning_logs.models import Entry
>>> Entry.objects.all()
Output:
<QuerySet [<Entry: The opening is the first part of the game, roughly ...>, <Entry: In the opening phase of the game, it’s important t ...>, <Entry: One of the most important concepts in climbing is ...>]>
You can retrieve the queryset and store it in a variable, then look through the variable the same way you loop through a list. Django automatically assigns a unique id to each entry wtihin a table (this id serves as the primary key) You can access the id and print it out as shown in the example below:
Example:
>>> from learning_logs.models import Topic
>>> topics=Topic.objects.all()
>>> for topic in topics:
... print(topic.id, topic)
...
Sample Output:
1 Chess
2 Rock Climbing
You can limit results by applying a filter. Filtering by id is one way to ensure that a single row of data is retrieved
Syntax: variable = ClassName.objects.get(id=#)
Example:
>>> t=Topic.objects.get(id=1)
To access anything within the row, prefix the field entry with the variable
>>>t.text
>>>t.date_added
Sample Output
>>> t=Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2021, 3, 16, 17, 49, 18, 148785, tzinfo=<UTC>)
>>> t.id
1
You can use filtered varibles to retrieve data in related models.
Syntax:
primaryModelVariable = ClassName.objects.get(id=#)
primaryModelVariable.classname_lowercase_set.all()
Example:
>>>t= t=Topic.objects.get(id=1)
>>>t.entry_set.all()
Sample output:
<QuerySet [<Entry: The opening is the first part of the game, roughly ...>, <Entry: In the opening phase of the game, it’s important t ...>]>
>>>
To see a video demonstration and explanation, view: https://youtu.be/A96QV4Nqe3c
1. Go into the command prompt and make sure the Learning_Log directory is the current directory and your virtual environment is active
2. Activate Django shell
python manage.py shell
3. Enter the following sequence of commands to verify the Topic structure and view the id that Django created (commands you need to enter are in bold, output is not):
>>> from learning_logs.models import Topic
>>> topics=Topic.objects.all()
>>> for topic in topics:
... print(topic.id,topic)
...
1 Chess
2 Rock Climbing
>>> t=Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2021, 3, 16, 17, 49, 18, 148785, tzinfo=<UTC>)
>>> t.id
1
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the game, roughly ...>, <Entry: In the opening phase of the game, it’s important t ...>]>
>>>
4. Enter the following sequence of commands to verify the Entry structure and view the id that Django created (commands you need to enter are in bold, output is not)
>>> from learning_logs.models import Entry
>>> ent=Entry.objects.all()
>>> for e in ent:
... print (e.id,e)
...
1 The opening is the first part of the game, roughly ...
2 In the opening phase of the game, it’s important t ...
3 One of the most important concepts in climbing is ...
5. Exit the shell, by typing exit( ) and pressing enter
Creating a web page involves defining URLs, creating views and writing templates. It doesn't matter what order you perform these tasks in.
In general, URLs are used to display views. Views are often rendered using templates which contain the page structure.
We will be working with the following files:
We are going to look at mapping URLs first, followed by creating the view and template.
Mapping a URL involves telling Django which URL goes to which View.
When a user makes a page request, the Django controller looks for the corresponding view by checking the url.py file and returning the HTML response or a 404 not found error. The most important thing in the url.py file is the urlpatterns list which is where you define mapping between URLs and views.
URLs can include parameters, in addition to the name of the page you want to display. When mapping a URL, you provide Django the pattern which includes the page name and any parameters it may be passed.
Syntax: path('request',ViewsFunctionName,NameIndex)
Where
NOTE: When request is entered as ' ' the default address, localhost:8000 is used
Example (retrieved from https://docs.djangoproject.com/en/3.1/topics/http/urls/, March 2021):
from django.urls import path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
By default, the url.py file is in the main project folder and contains a pattern for the admin site which is why you saw that site when you first launched the app.
Example of default settings in learning_log/url.py: The first line imports a function to manage admin URLs. The second line imports a module for URLs and is included in all url.py files. "admin" in the path is what you enter in the address bar and admin.site.urls defines all URLs that can be requested from the admin site
At the top of the file, there are comments which provide some instruction for entering URLs. You can also refer to documentation at: https://docs.djangoproject.com/en/3.1/topics/http/urls/
To add a new path, just edit the urlpatterns and enter the path below the existing path (make sure you place a comma at the end to set up for additional paths you may want to enter)
Python allows more than one url.py file. It is not unusual to create a url.py file in the same directory as the views.py file
To see a video demonstration and explanation, view: https://youtu.be/etLu1jEyvvo
We want to add a urls.py file to our learning_logs directory which is where our view file is located. By default, Django will go to learning_log/urls.py to look for URLs. We need to edit that file and tell Django to look for a urls.py file in the learning_logs directory. Then, we will go into the learning_logs directory and create our new urls.py file.
1. Open learning_log/urls.py in VSCode
2. Add the code on page 395 to include all learning_log urls
3. Save your changes
4. Open learning_logs and create a new urls.py file. Add the code at the bottom of page 395 (it is also shown below)
Line 3 tells Django the views.py file is located in the same directory as the active urls.py file
Line 5 app_name serves as a namespace and is designed to give urls.py a unique app_name (projects have more than 1 urls.py file, it helps to give them unique names)
Lines 6-9 define the path to the page. Because the request is blank, it will be used when the app first launches and the address is localhost:8000 views.index is the function in the views.py file that should be executed and name='index' is a name we can reference this URL with in code
5. Save your changes
In Django, you create views by adding functions to the views.py file. Views in Django are more like controllers in an MVC project. They don't contain any html. They handle the users request, prepare data and use a render function to display the appropriate template.
The render() function takes the request object as its first argument, a template name as its second argument and a dictionary as its optional third argument. It returns an HttpResponse object of the given template rendered with the given context.
Example: In the example, the request is the user's request which Django passes to the function and index.html is the template that will be rendered
def index(request):
"""The home page for Learning Log."""
return render(request, 'learning_logs/index.html')
IMPORTANT:
For Django to render your html template, you need to create a very specific directory structure.
You will have a project folder and a plural version of that project folder. Inside the plural version, you need to create a templates directory and inside that, you need another plural version of your project folder. Inside all of that is where you add the html templates
Here's an example:
If you do not create the structure correctly, you will get errors when you run the app.
A template is a text file that can contain HTML, xml, csv and code. (They are similar to C# razor pages.) We will be creating templates containing code and HTML.
Example:
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
Variables re entered into a template with two sets of curly braces on each side
Syntax: {{ variable}}
When the template rendering engine encounters a variable, it replaces it with the result.
Variables can include any combination of alphnumeric characters and underscores. They cannot include spaces.
Variables with dots tell Django you have a dictionary, attribute, method or index AND Django tries to look up the value. You shouldn't include a dot in a variable name unless you are trying to access a dictionary, attribute, method or index.
Example:
<h1>{{ section.title }}</h1>
section.title will capitalize the value stored in section and display it using heading 1
You can apply filters to variables before they are displayed. This is done using a pipe operator to apply the filter. The pipe operator is a vertical line, | , that you place between the variable and the filter
Syntax: {{variable | filter1 | filter2 | filtern }}
Example #1: {{ name | lower }} the value stored in name is filtered through the lower filter which converts it to lowercase
Example #2: {{ bio|truncatewords:30 }} the value stored in bio will be truncated after 30 words
Example #3: {{ value | default:"nothing"}} if the variable is empty, store "nothing" in it; otherwise, store it's value
Example #4: {{ value|length }} returns the length of the variable
For a complete list of filters, see: https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#ref-templates-builtins-filters
Tags are more complex than variables. Some create text in the output, some control flow by performing loops or logic, and some load external information into the template to be used by later variables.
Django ships with about two dozen built-in template tags. Some involve opening and closing tags and others do not.
Syntax: {% tag %} ... tag contents ... {% endtag %}
Commonly used tags include:
Used to generate URLs
Example: The example generates a URL matching the pattern added to learning_logs/urls.py. The name index referes to the index.html page. learning_logs is a namespace (it comes from the value we assigned to app_name in the learning_logs/urls.py file)
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
Used to create a for loop in a template
Example: The example assumes you are retrieving athlete.name from a list called athlete_list
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
Used to create an nested if structure in a template
Example:
{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
Athletes should be out of the locker room soon!
{% else %}
No athletes.
{% endif %}
Example combining if and for:
{% if athlete_list|length > 1 %}
Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
Athlete: {{ athlete_list.0.name }}
{% endif %}
extends is used for template inheritance (we will be using this for parent/child templates). When extend is used, it locates the parent template first and then looks for block statements in the child that should replace the generic content in the parent
block statements are used in the base to identify sections of content that may change. They are used in the child template to identify sections that should override the base (parent) template.
It is considered best practice to create a parent template that all html files can inherit from. The parent template will ensure that all pages have the same look and feel (for those of you familiar with MVC, this is similar to the _layout page all views are displayed in).
In Django, the parent template is often named base.html. It should be located in the same directory as all your html files: /projectName/projectNames/templates/projectNames/ (i.e. learning_log/learning_logs/templates/learning_logs/ )
base.html example: The base html includes empty content blocks that the child pages will fill in. It is designed to provide a consistent look for the site.
child template example - content in the base will be replaced by content in the child. the title will be replaced and the bock content will be replaced. The sidebar wasn't overridden in the child template, so that will NOT be replaced.
After the child and parent are combined, the ending output may look something like this:
For more on templates, see: https://docs.djangoproject.com/en/3.1/ref/templates/language/
If you need to include comments OR comment out a section of a template, use the comment syntax: {# #}.
To see a video demonstration and explanation, view: https://youtu.be/Jpp3ydSsTf8
1. Open learning_logs/views.py in VSCode
2. Add the code on page 396 to create the index function which will be used to render the index.html template
3. Open the learning_logs directory and create a new folder named templates.
4. Open learning_logs/templates and create a new folder named learning_logs
5. Inside learning_logs/templates/learning_logs, create the index.html template and add the code shown on page 397
NOTE: If you don't follow the conventions for creating the structure correctly, you will have errors when you run the app
6. Save your changes
7. Run your app (if your app is running, enter localhost:8000. It should automatically route to your new index.html page. If you see an error, double check the directory names you have created, your structure should match the example shown below:
8. Create the base.html file in the same directory as index.html (this will serve as the parent template) See page 399
9. Modify the index.html file so it extends from base.html (making it a child template) See pages 399-400
10. Run the app and test your changes
In Django, you can retrieve data from a database model using a queryset. The data can be passed along to the template in the render function.
NOTE: You can practice data retrieval commands in the Django shell to make sure they work BEFORE you code them in a view function. We did that in hands on #10. Now, we just need to retrieve the data in a view and pass it to a template.
In the views.py file, you need to:
1) import the model
2) retrieve the data and store it in a variable
3) add the variable to a context dictionary object.
4) pass the context dictionary object to the template using the render function
In the template, the context dictionary key becomes the name you will use to access the data. The values are what you want to display in your web page.
Example: In the example below, topic.objects.order_by('date_added') retrieves all the topics in the Topic table and sorts them by date. It adds the topics to a context dictionary object which is passed to the topics.html template.
from django.shortcuts import render
from .models import Topic
def topics(request):
"""Show all topics."""
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
To retrieve topics without sorting, we could have used:
topics = Topic.objects.all()
To retrieve a specific topic, we would need the topic_id passed into the function along with the request
def topics(request, topic_id):
"""Show one topic."""
topics = Topic.objects.get(id=topic_id)
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
Because our Entry table is related to the Topic table in a many-to-one relationship, we can access entries for specific topics in the view function and pass both the topic and it's entries to the template using the context dictionary.
def topics(request, topic_id):
"""Show one topic and it's entries."""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries':entries}
return render(request, 'learning_logs/topic.html', context)
Anytime you are referring to data in a model, you will use the object representing an instance of the model and a period followed by the attribute you are accessing
Variables are often given similar names, but will have an underscore before the attribute.
For example, in the code we are working with topic.id refers to an instance of the Topic model and topic_id is a variable storing an ID. So, one contains data from the table and the other contains a value that has been assigned to it. It is important that you recognize where values are coming from when working with the code.
To see a video demonstration and explanation, view: https://youtu.be/UaTjVZwHlKg
1. Edit learning_logs/urls.py and add the path to the topics view as directed on page 401
2. Save your changes
3. Edit learning_logs/views.py and add the topics function as directed on page 401
4. Save your changes
5. Create the topics.html template as directed on page 402 (it should be in the same directory as the index.html template)
6. Save your changes
7. Edit base.html and add a link to the topics page as directed on page 403
8. Save your changes
9. Run the app in the browser (or refresh the browser if it is already running). You should be able to click the links and display both the index.html page and the topics.html page
1. Edit learning_logs/urls.py and add the path to the topic view as directed on page 404 (keep the topics information there and add a new entry below it). There will be a view that displays all the topics and another view that will display a single topic and all of its entries.
2. Save your changes
3. Edit learning_logs/views.py and add the topic function as directed on page 404 (you will have a topics function, a topic function,and an index function)
A few keypoints to remember:
topic_id is a parameter being passed from the address bar (if the user enters localhost:8000/topic/1 ) or from the topic screen if a topic is selected
Topic.objects.get(id=topic_id) is retrieving the topic associated with the id that was passed as a parameter. id is the name of the column in the table that Django generated as the primary key when the table was created.
topic.entry_set.order_by("-date_added") is using the topic object created by Topic.objects.get to retrieve the related entries from the Entry table. It is using entry_set to do that (entry is the name of the related table) order_by is used to sort the entries.
context is a dictionary that is passed to the template. It contains all the data the template needs to display to the user
learning_logs/topic.html is the template it needs to send the data to
4. Save your changes
5. Create the topic.html template as directed on page 405 (it should be in the same directory as the index.html template)
6. Save your changes
7. To get to our new topic.html page, we will select a link in the topics.html page. Edit topics.html and add a link to the topic page as directed on page 405
8. Save your changes
9. Run the app in the browser (or refresh the browser if it is already running). You should be able to click the links and display both the index.html page and the topics.html page. To get to our new page, you can add the id parameter to the address and enter it directly or you can select a link in the topics page
To test the parameter on the address bar, type:
localhost:8000/topics/1
localhost:8000/topics/2
To test the links, display the topics page showing Chess and Rock Climbing, then click the Chess or Rock Climbing link
For this assignment, submit a screenshot of the following screens running in the web browser:
You do not need to put anything on GitHub yet.
To see a video demonstration and explanation, view: https://youtu.be/5dVIpozfSLA
1. Complete Try-It-Yourself 18-4 on page 394. To see some helpful hints for Try-It-Yourself 18-4, view: Steps for 18-4
NOTE: You should only add toppings 1 time. After you add a topping, you can associate it with each pizza that uses it without entering it again. Just select the topping, click the pizza list arrow, choose the pizza you want it applied to and click Save.
Example:

2. Complete Try-It-Yourself 18-6 on page 398. For some helpful hints, see: Steps for 18-6
3. Complete Try-It-Yourself 18-8 on page 406. For some helpful hints, see: Steps for 18-8 If you have problems with the assignment, this is where I think they will occur. The urls.py, views.py and templates are all interconnected. If you don't understand how everything works, it is very easy to get an error.
Submit the following screenshots of your pizza app running in the web browser:
a Home page that links to the Pizzas and Toppings (index.html page)
b) A Pizza Summary page with links to display each pizza and it's toppings (pizzas.html)
c) A Pizza Detail page that shows one pizza with all it's toppings (pizza.html)
You do not need to put anything on GitHub yet, just submit the screenshots.
Upload the following screenshots of the app running in the browser and displaying data:
| ScreenShot | Points |
|---|---|
Learning Log index.html |
3 |
Learning Log topics.html |
4 |
Learning Log topic.html |
4 |
Pizzeria index.html |
4 |
Pizzeria pizzas.html (summary page) |
5 |
Pizzeria pizza.html (details page) |
5 |
| Total Points | 25 |