Lecture 3 Notes
Lecture 3 Notes
Lecture 3 Notes
Introduction
Web Applications
HTTP
Django
Routes
Templates
o Conditionals:
o Styling
Tasks
Forms
o Django Forms
Sessions
Introduction
So far, we’ve discussed how to build simple web pages using
HTML and CSS, and how to use Git and GitHub in order to keep
track of changes to our code and collaborate with others. We
also familiarized ourselves with the Python programming
language.
Today, we’ll work on using Python’s Django framework in order
to create dynamic applications.
Web Applications
So far, all of the web applications we’ve written have been static.
This means that every single time we open that web page, it looks
exactly the same. Many websites we visit every day, however,
change every time we visit them. If you visit the websites of
the New York Times or Facebook, for example, you’ll most likely see
different things today than you will tomorrow. For large sites like
those, it would be unreasonable for employees to have to manually
edit a large HTML file every time a change is made, which is
where dynamic websites can be extremely useful. A dynamic
website is one that takes advantage of a programming language
(such as Python) to dynamically generate HTML and CSS files.
During this lecture, we’ll learn how to create our first dynamic
applications.
HTTP
HTTP, or HyperText Transfer Protocol, is a widely-accepted protocol
for how messages are transfered back and forth across the internet.
Typically, information online is passed between a client (user) and a
server.
In this protocol, the client will send a request to the server, that
might look something like the one below. In the example
below, GET is simply a type of request, one of three we’ll discuss in
this course. The / typically indicates that we’re looking for the
website’s home page, and the three dots indicate that we could be
passing in more information as
well.
200 is just one of many status codes, some of which you may have
seen in the
past:
Django
Django is a Python-based web framework that will allow us to write
Python code that dynamically generates HTML and CSS. The
advantage to using a framework like Django is that a lot of code is
already written for us that we can take advantage of.
Routes
Now, in order to get started with our application:
Now that we’ve had some success, let’s go over what just happened
to get us to that point:
Now, let’s take a look at how we can add more than one view to our
application. We can follow many of the same steps within our
application to create pages that say hello to Brian and David.
Inside views.py:
def index(request):
return HttpResponse("Hello, world!")
def brian(request):
return HttpResponse("Hello, Brian!")
def david(request):
return HttpResponse("Hello, David!")
Inside urls.py (within our application)
urlpatterns = [
path("", views.index, name="index"),
path("brian", views.brian, name="brian"),
path("david", views.david, name="david")
]
Now, our site remains unchanged when we visit localhost:8000/hello,
but we get different pages when we add brian or david to the
URL:
Many sites are parameterized by items included in the URL. For
example, going to www.twitter.com/cs50 will show you all of CS50’s
tweets, and going to www.github.com/cs50 will bring you to CS50’s
GitHub page. You can even find your own public GitHub repositories
by navigating to www.github.com/YOUR_USERNAME!
Templates
So far, our HTTP Responses, have been only text, but we can include
any HTML elements we want to! For example, I could decide to
return a blue header instead of just the text in our index function:
def index(request):
return HttpResponse("<h1 style=\"color:blue\">Hello, world!</h1>")
It would get very tedious to write an entire HTML page
within views.py. It would also constitute bad design, as we want to
keep separate parts of our project in separate files whenever
possible.
This is why we’ll now introduce Django’s templates, which will allow
us to write HTML and CSS in separate files and render those files
using Django. The syntax we’ll use for rendering a template looks
like this:
def index(request):
return render(request, "hello/index.html")
Now, we’ll need to create that template. To do this, we’ll create a
folder called templates inside our app, then create a folder
called hello (or whatever our app’s name is) within that, and then
add a file called index.html.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
</body>
</html>
You’ll noticed that we used some new syntax: double curly brackets.
This syntax allows us to access variables that we’ve provided in
the context argument. Now, when we try it
out:
Now, we’ve seen how we can modify our HTML templates based on
the context we provide. However, the Django templating language
is even more powerful than that, so let’s take a look at a few other
ways it can be helpful:
Conditionals:
But this website will change on Christmas day, when the website will
say YES. To make something like this for ourselves, let’s try
creating a similar application, where we check whether or not it is
New Year’s Day. Let’s create a new app to do so, recalling our
process for creating a new app:
1. Create another urls.py file within our new app’s directory, and
update it to include a path similar to the index path in hello:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Is it New Year's?</title>
</head>
<body>
{% if newyear %}
<h1>YES</h1>
{% else %}
<h1>NO</h1>
{% endif %}
</body>
</html>
In the code above, notice that when we wish to include logic in our
HTML files, we use {% and %} as opening and closing tags around
logical statements. Also note that Django’s formatting language
requires you to include an ending tag indicating that we are done
with our if-else block. Now, we can open up to our page to see:
Now, to get a better idea of what’s going on behind the scenes, let’s
inspect the element of this page:
Notice that the HTML that is actually being sent to your web browser
includes only the NO header, meaning that Django is using the
HTML template we wrote to create a new HTML file, and then
sending it to our web browser. If we cheat a little bit and make sure
that our condition is always true, we see that the opposite case is
filled:
def index(request):
now = datetime.datetime.now()
return render(request, "newyear/index.html", {
"newyear": True
})
Styling
h1 {
font-family: sans-serif;
font-size: 90px;
text-align: center;
}
Now, to include this styling in our HTML file, we add the line {% load
static %} to the top of our HTML template, which signals to Django
that we wish to have access to the files in our static folder. Then,
rather than hard-coding the link to a stylesheet as we did before,
we’ll use some Django-specific syntax:
Tasks
Now, let’s take what we’ve learned so far and apply it to a mini-
project: creating a TODO list. Let’s start by, once again, creating a
new app:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tasks</title>
</head>
<body>
<ul>
{% for task in tasks %}
<li>{{ task }}</li>
{% endfor %}
</ul>
</body>
</html>
Notice here that we are able to loop over our tasks using syntax
similar to our conditionals from earlier, and also similar to a Python
loop from Lecture 2. When we go to the tasks page now, we can see
our list being
rendered:
Forms
Now that we can see all of our current tasks as a list, we may want
to be able to add some new tasks. To do this we’ll start taking a look
at using forms to update a web page. Let’s begin by adding another
function to views.py that will render a page with a form for adding a
new task:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tasks</title>
</head>
<body>
<h1>Add Task:</h1>
<form action="">
<input type="text", name="task">
<input type="submit">
</form>
</body>
</html>
However, what we’ve just done isn’t necessarily the best design, as
we’ve just repeated the bulk of that HTML in two different files.
Django’s templating language gives us a way to eliminate this poor
design: template inheritance. This allows us to create
a layout.html file that will contain the general structure of our page:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tasks</title>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
Notice that we’ve again used {%...%} to denote some sort of non-
HTML logic, and in this case, we’re telling Django to fill this “block”
with some text from another file. Now, we can alter our other two
HTML files to look like:
index.html:
{% extends "tasks/layout.html" %}
{% block body %}
<h1>Tasks:</h1>
<ul>
{% for task in tasks %}
<li>{{ task }}</li>
{% endfor %}
</ul>
{% endblock %}
add.html:
{% extends "tasks/layout.html" %}
{% block body %}
<h1>Add Task:</h1>
<form action="">
<input type="text", name="task">
<input type="submit">
</form>
{% endblock %}
Notice how we can now get rid of much of the repeated code
by extending our layout file. Now, our index page remains the same,
and we now have an add page as well:
Next, it’s not ideal to have to type “/add” in the URL any time we
want to add a new task, so we’ll probably want to add some links
between pages. Instead of hard-coding links though, we can now
use the name variable we assigned to each path in urls.py, and create
a link that looks like this:
app_name = "tasks"
urlpatterns = [
path("", views.index, name="index"),
path("add", views.add, name="add")
]
We can then change our links from
simply index and add to tasks:index and tasks:add
Django Forms
While we can create forms by writing raw HTML as we’ve just done,
Django provides an even easier way to collect information from a
user: Django Forms. In order to use this method, we’ll add the
following to the top of views.py to import the forms module:
class NewTaskForm(forms.Form):
task = forms.CharField(label="New Task")
Now, let’s go through what’s going on in that class:
{% extends "tasks/layout.html" %}
{% block body %}
<h1>Add Task:</h1>
<form action="{% url 'tasks:add' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>
<a href="{% url 'tasks:index' %}">View Tasks</a>
{% endblock %}
There are several advantages to using the forms module rather than
manually writing an HTML form:
else:
def index(request):
That’s all for this lecture! Next time we’ll be working on using
Django to store, access, and manipulate data.