Creating a simple app
Assignment 5 is due tomorrow.
What happens when you do this?
$> pip install Django
import django
django.VERSION # gives you 4.0.4
django-admin is installed in your environment.It's Django’s command-line utility for administrative tasks. It can:
Let's create a new project so that users can browse this painstakingly curated collection of information about cheeses and rate cheeses they have tried.
$> django-admin startproject cheeseshop
Run this command in the directory where you want to create your Django project.
Generally it's a good idea to run it in the root directory of a Github project you want to keep your site in.
What did startproject do?
cheeseshop/
manage.py
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
It created some files.
What is manage.py for?
cheeseshop/
manage.py
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
django-admin; it does all the same things but specific to your project.django-admin and start using manage.py to do things.manage.py.Let's use this utility to start up a Django webserver:
$> python manage.py runserver
This will start up a small, simple webserver you can use for local development. You can visit your website at http://127.0.0.1:8000/
What is 127.0.0.1, aka localhost?
Let's look at our files again:
cheeseshop/
manage.py
db.sqlite3
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
Wait, where did this db.sqlite3 come from? It wasn't there before.
What is settings.py for?
cheeseshop/
manage.py
db.sqlite3
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
What is urls.py for?
cheeseshop/
manage.py
db.sqlite3
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
What about asgi.py and wsgi.py?
cheeseshop/
manage.py
db.sqlite3
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py

WSGI stands for Web Server Gateway Interface. It is a specification that describes how a web server communicates with Python web applications.
So far we've used the Django development web server, but if you were to deploy your app in production, you would use a real server.
This server would communicate without our Django app via WSGI, and use the wsgi.py file to do it.
Let's create a view to replace the default Django one.
cheeseshop/
manage.py
db.sqlite3
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
views.py
cheeseshop/views.py
from datetime import datetime
from django.http import HttpResponse
def index(request):
now = datetime.now()
return HttpResponse(f"It is now {now}.")
cheeseshop/urls.py
from django.contrib import admin
from django.urls import path
from cheeseshop.views import index
urlpatterns = [
path("", index),
]
Note that we didn't have to do anything ohter than go to our browser and reload the page.
The Django webserver restarts whenever it sees your Python code has changed.
This is pretty boring. Can we spice it up a bit? Maybe add some HTML?
Create a folder in the Django project root called "templates".
index.html inside that.
cheeseshop/
manage.py
db.sqlite3
cheeseshop/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
views.py
templates/
index.html
cheeseshop/views.py
from datetime import datetime
from django.shortcuts import render
def index(request):
now = datetime.now()
return render(request, "index.html", {"now": now})
Templates are rendered with a context.
A context is a list of variables that will be available in a template. It's represented as a dictionary where the keys are the variable names and the values are the variable values.
{
"date": datetime.now(),
"name": "Bob Smith",
"age": 28
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cheese Shop</title>
</head>
<body>
<h1>Cheese Shop</h1>
<p>Welcome!</p>
<p>Today is: {{ now }} </p>
</body>
</html>
So far we've...
cheeseshop/views.pycheeseshop/urls.pytemplates/index.html

Explicit is better than implicit.
We forgot a step
cheeseshop/views.pycheeseshop/urls.pytemplates/index.htmlcheeseshop/settings.py (partial)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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',
],
},
},
]
cheeseshop/settings.py (partial)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['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',
],
},
},
]