Django framework notes
Create Virtual Environment
py -m venv myenv
Activate the virtual environment:
On Windows: myenv\Scripts\activate
On Unix or MacOS: source ./myenv/bin/activate
Deactivate the virtual environment:
deactivate
pip install django
- install Django
django-admin startproject myapp
- create new Django project
django-admin startproject myapp .
- create new Django project within current directory
py manage.py runserver
- run server
py manage.py createsuperuser
- create superuser
django-admin startapp lynx
- create new app
py manage.py makemigrations
- make migrations
py manage.py migrate
- run migrations
In the main project's urls.py
file, add the path
.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('lynx.urls')),
]
In urls.py
:
from django.urls import path
from . import views
urlpatterns = [
path('', views.home),
path('hello', views.hello, name='hello'),
]
In views.py
:
from django.http import HttpResponse
def hello(req):
return HttpResponse('Hello there!', content_type='text/plain')
or
from django.http import HttpResponse
def hello(req):
http_response = HttpResponse('', content_type='text/plain')
http_response.write('Ahoy!')
return http_response
launch request with: http localhost:8000/hello
By default, static files are served from the static
subdirectory of each module.
Additional static directories can be specified in STATICFILES_DIRS
in settings.py
.
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ article.title }}</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
{{ article.title }}
<br>
{{ article.description }}
</body>
</html>
Static files are loaded with {% load static %}
and later referenced with command such as {% static 'css/style.css' %}
.
In urls.py
, add the user-agent/
endpoint.
from django.urls import path
from . import views
urlpatterns = [
path('user-agent/', views.user_agent, name='user-agent' ),
]
From the HttpRequest
object get the user agent and return it with HttpResponse
.
from django.http import HttpRequest, HttpResponse
def user_agent(req: HttpRequest):
ua = req.META['HTTP_USER_AGENT']
return HttpResponse(ua, content_type='text/plain')
In views.py
:
from django.http import HttpResponse, HttpResponseNotFound
def get_image(req):
sid_path = 'lynx/images/sid.png'
try:
with open(sid_path, 'rb') as f:
data = f.read()
resp = HttpResponse(data, content_type='image/png')
# resp['Content-Disposition'] = 'attachment; filename="sid.png"'
resp['Content-Disposition'] = 'inline; filename="sid.png"'
except IOError:
resp = HttpResponseNotFound('<h2>file does not exist</h2>')
return resp
or
from django.http import FileResponse, HttpResponseNotFound
def get_image(req):
sid_path = 'lynx/images/sid.png'
try:
resp = FileResponse(open(sid_path, 'rb'), as_attachment=False,
filename='sid.png')
except IOError:
resp = HttpResponseNotFound('<h2>file does not exist</h2>')
return resp
The FileResponse
closes the file automatically.
Install pillow: pip install pillow
.
In settings.py
:
MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
In main urls.py
add:
from django.conf import settings
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
Model:
class Article(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
banner = models.ImageField(default='flag.png', blank=True)
created_at = models.DateTimeField(auto_now_add=True)
...
Install module: pip install django-debug-toolbar
In settings.py
:
INSTALLED_APPS = [
...
'django.contrib.staticfiles',
'debug_toolbar',
'lynx',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
...
]
In main ulrs.py
file:
urlpatterns = [
...
path('__debug__/', include('debug_toolbar.urls'))
]
Resolve JavaScript files are resolving to the wrong content type
error on
Windows:
import mimetypes
mimetypes.add_type("application/javascript", ".js", True)
DEBUG_TOOLBAR_CONFIG = {
"INTERCEPT_REDIRECTS": False,
}
INTERNAL_IPS = [
'127.0.0.1',
]
Message object.
from django.db import models
class Message(models.Model):
text = models.CharField(max_length=255)
def __str__(self):
return self.text
Fetch messages and send them in paginator object.
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage
from .models import Message
def index(request):
messages = Message.objects.all()
paginator = Paginator(messages, 20)
try:
page_num = request.GET.get('page', 1)
page = paginator.page(page_num)
except EmptyPage as e:
page = paginator.page(1)
ctx = {'messages': page}
return render(request, 'index.html', ctx)
Display messages in template.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% for message in messages %}
{{ message.text }}
<br>
{% endfor %}
{% if messages.has_previous %}
<a href="{% url 'index' %}?page={{messages.previous_page_number}}">Previous page</a>
{% endif %}
{% if messages.has_next %}
<a href="{% url 'index' %}?page={{messages.next_page_number}}">Next page</a>
{% endif %}
</body>
</html>
A slug is a user and seo friendly way of creating meaningful URLs to refer to our documents.
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
slug = models.SlugField(max_length=255)
def __str__(self):
return self.title
The Article
model contains the models.SlugField
attribute.
from django.contrib import admin
from . models import Article
@admin.register(Article)
class (admin.ModelAdmin):
list_display = ['title', 'body', 'slug']
list_filter = ['title', 'body', 'slug']
search_fields = ['title', 'body']
prepopulated_fields = {'slug': ('title',)}
The ArticleAdmin
model causes the slug to be automatically generated when writing a
title to our article using prepopulated_fields
.
from django.shortcuts import render
from . models import Article
def index(request):
articles = Article.objects.all()
ctx = {'articles': articles}
return render(request, 'index.html', ctx)
def show_article(request, slug):
content = Article.objects.get(slug=slug)
ctx = {'content': content}
return render(request, 'show_article.html', context=ctx)
In the home page, we show all articles and in the show_article.html
we show the contents of the
currently selected article. We retrieve the articles by their slug via Article.objects.get(slug=slug)
.
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('<slug:slug>', views.show_article, name='show-article'),
]
We use <slug:slug>
to map the slug to the show-article view.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% for article in articles %}
<a href="{{ article.slug }}">{{ article.title }}</a> <br>
{% endfor %}
</body>
</html>
In the home page (index.html
), we list all artiles. The links are the slugs of the articles.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>{{ content.title }}</h2>
{{ content.body }}
</body>
</html>
We display the title an the body of the article in show_article.html
.
The get_object_or_404
is a shortcut to send 404 page if an object is not found.
from django.http import Http404
from django.shortcuts import render, get_object_or_404
from .models import Product
def product_detail(request, pid):
# try:
# product = Product.objects.get(id=pid)
# ctx = {'product': product}
# except Product.DoesNotExist:
# raise Http404
product = get_object_or_404(Product, id=pid)
ctx = {'product': product}
return render(request, 'product_detail.html', ctx)
We get a Product
by its id.
from django.urls import path
from . import views
urlpatterns = [
path("products/<pid>/", views.product_detail, name ="product-detail"),
]
The products/<pid>/
path automaticall adds pid
parameter to the views.product_detail
function.
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
def __str__(self):
return self.name
A Product
model.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>
{{ product.name}} - {{ product.price }}
</p>
</body>
</html>
Display product name and price.