django beginner workshop¶
Basics¶
django¶
- MVT-Webframework
- Python 2/3
- Aktuelle Version 1.11 LTS
- Pluggability
- Don’t repeat yourself (DRY)
- Introspection
Note
- Benannt nach Django Reinhardt, Gitarrist
- Kommt aus der Zeitungswelt
Wo wird django genutzt?¶
- disqus
- Mozilla
- NASA
Was beinhaltet django?¶
- Webserver
- Middleware
- URL-Dispatcher
- Views
- Models: ORM-Mapper
- Form-Validator
- Admin-Interface
- Templates
- …
(Stark vereinfachter) Requestablauf¶

Note
Ein Request Object hat alle Informationen zu dem Request. Unter anderem Context-Variablen, Post/Get, URL, Languages.
Bei Fragen¶
- Offizielle Dokumentation: https://docs.djangoproject.com/
Das Projekt¶
Ein Portfolio¶
Seiten
- Startseite mit Projektübersicht
- Projektdetailseite
- Kontaktformular
Design nach Bedarf (http://getbootstrap.com/)
Datenmodell für unsere Seite¶

virtualenv (venv)¶
- Kapseln der Python Pakete in einer unabhängigen “Installation”
- Unterschiedliche Projekte können unterschiedliche Abhängigkeiten bekommen
- Volle Unterstützung von pip
- Keine root-Rechte für Installation von Paketen
venv einrichten¶
user@hostname:$ virtualenv venv
New python executable in venv/bin/python
Installing setuptools, pip...done.
user@hostname:$ source venv/bin/activate
(venv)user@hostname:$ deactivate
user@hostname:$
Note
Man kann auch virtualenv wrapper verwenden. Je nach Situation kann dieser Arbeit abnehmen.
django installieren¶
$ pip install django==1.11.*
$ pip install psycopg2 # Für Postgres
$ pip install Pillow # Für Bilder
$ pip freeze
Warning
Für diesen Befehl und für alle weiteren Befehle muss man die venv aktiviert haben.
django installieren 2¶
$ python -c "import django; print(django.get_version())"
1.8.15
Was wurde erstellt?¶
Note
Besonders wichtig sind:
- manage.py
- settings.py
- urly.py
- wsgi.py
runserver¶
- Einfacher debugging Server
- NICHT(!) produktiv nutzen
- autoreload (fehlerhaft)
runserver starten¶
$ python manage.py runserver 0.0.0.0:8000
Performing system checks...
System check identified no issues (0 silenced).
You have unapplied migrations; your app may not work properly until they are applied.
Run 'python manage.py migrate' to apply them.
October 04, 2017 - 16:32:20
Django version 1.11.6, using settings 'portfolio.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
View¶
Die erste “App” erstellen¶
- Apps sind gekapselte Plugins für django
- “Alles” muss und wird in einer App gekapselt
$ python manage.py startapp core
class: | slidecenter |
---|
Was wurde erstellt?¶
App in den INSTALLED_APPS
eintragen¶
in portfolio/settings.py
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core',
)
Die erste View¶
In core/views.py
:
from django.http import HttpResponse
def index(request):
return HttpResponse("hello world!")
URL-Mapping¶
- URLs sind so wichtig wie Code
- Keine IDs => 123
- Nur Slugs => meine-projektseite
- http://en.wikipedia.org/wiki/Semantic_URL
App urls.py¶
core/urls.py
from django.conf.urls import url
from core import views
urlpatterns = [
url(r'^$', views.index, name='index')
]
Note
Viele regex Möglichkeiten, unter anderem mit Variablenzuweisung.
Importieren in der globalen Datei¶
portfolio/urls.py
from django.conf.urls import include, url
from django.contrib import admin
from core import urls as core_urls
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^core/', include(core_urls))
]
Note
In der realen Welt wird man das vermutlich nicht so sauber trennen. Hier für den Workshop arbeiten wir aber so sauber wie möglich!
Recap: Wo stehen wir gerade?¶

Templates¶
Template Language¶
- Absichtlich:
- Einfacher Syntax
- !KEINE LOGIK!
- Wurde von vielen kopiert
Template Language¶
- Tags:
{% if %}
,{% endif %}
,{% load static %}
- Filter:
{{project.name|lower|striptags|truncatewords:2 }}
- Vererbung:
{% extends "base.html" %}
,{% block content %}
Note
- Man kann sehr einfach eigene Tags/Filter schreiben https://docs.djangoproject.com/en/1.7/ref/templates/builtins/
Template-HTML¶
core/templates/index.html
<!DOCTYPE html>
<html>
<head>
<title>Portfolio</title>
</head>
<body>
<h1>Hi!</h1>
{{ message }}
</body>
</html>
Template in der View verwenden¶
core/views.py
from django.template import RequestContext
def index(request):
context_dict = {'message': "Ich komme aus dem context_dict"}
return render(request, 'index.html', context_dic)
Statische Medieninhalte¶
portfolio/settings.py
STATIC_URL = '/static/'
Note
Statische Inhalte sind anders zu behandeln als Medieninhalte.
Im Template¶
core/templates/index.html
{% load staticfiles %}
<img src="{% static 'example.jpg' %}" alt="Picture" />
Note
Das Bild dazu muss unter core/static/example.jpg liegen.
Assets einbinden¶
<link rel="stylesheet" href="{% static 'css/base.css' %}" />
<script src="{% static 'js/jquery.js' %}"></script>
Übung: “Über mich”-Seite¶
- Entwickele eine eigene “über mich”-Seite
- Url verlinkungen mit dem URL Tag: https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#url
Database¶
Das erste Model¶

Datenbank¶
- PostgreSQL
- MySQL
- SQLite
- Oracle
- (MSSQL)
- (NOSQL)
SQLite¶
portfolio/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_PATH, 'portfolio.db'),
}
}
Warning
Niemals SQLite produktiv nutzen
PostgreSQL¶
portfolio/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'db_name',
'USER': 'db_user',
'PASSWORD': 'db_user_password',
'HOST': ''
}
}
Models¶
- Beschreibung von Daten in Python-Objekten
- Wir bekommen “geschenkt”:
- auto Validierungen
- auto Forms
- auto Admin
Models¶
core/models.py
class Kategorie(models.Model):
name = models.CharField(max_length=128, unique=True, help_text="Der Name")
def __unicode__(self):
return self.name
class Project(models.Model):
category = models.ForeignKey("Kategorie", related_name="projects", null=True)
name = models.CharField(max_length=128, unique=True)
def __unicode__(self):
return self.name
Model Feld Typen¶
- CharField / TextField
- URLField
- IntegerField
- BooleanField
- ImageField
- DateField
- ForeignKey / OneToOneField / ManyToManyField
- …
Datenbank erstellen¶
$ python manage.py migrate
$ python manage.py makemigrations core
$ python manage.py migrate
Shell debugging¶
$ python manage.py shell
Shell debugging 2¶
>>> from core.models import Project
>>> print Project.objects.all()
[]
>>> p = Project(name="Test")
>>> print Project.objects.all()
[]
>>> p.save()
>>> print Project.objects.all()
[<Project: Test>]
>>> quit()
Note
- Daten lesen / schreiben:
- all()
- filter(…)
- get(…)
- order_by()
- save()
- Chaining bei QuerySets
- Field Lookups
- Genelle Informationen zum Query erstellen: https://docs.djangoproject.com/en/1.11/topics/db/queries/#field-lookups
class: | slidecenter |
---|
django Admin¶
Note
Der Admin funktioniert über Introspection im Gegensatz zu zum Beispiel Ruby on Rails.
django Admin: aktivieren¶
INSTALLED_APPS = (
'django.contrib.admin', #hier
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core',
)
Note
Bei neuen django Installationen ist der Admin schon aktiviert.
class: | slidecenter |
---|
django Admin Demo¶
Note
/admin
Models am admin registrieren¶
core/admin.py
from django.contrib import admin
from core.models import Project
admin.site.register(Project)
Populate-Skript¶
populate.py
import os
def populate():
Project.objects.get_or_create(name="myProject")
#....
for p in Project.objects.all():
print p
if __name__ == '__main__':
print "Starting Population script..."
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'portfolio.settings')
import django
django.setup()
from core.models import Project
populate()
Der Adminuser im Template¶
core/templates/index.html
{% if user.is_authenticated %}
nice to see you
{% else %}
who are you
{% endif %}
class: | slidecenter |
---|
Admin Showcase¶
Was so geht …
Model-Templates¶
Models im Template¶
- Liste
- View erweitern
- Template erweitern
- Detailseite
- Neue View + URL-Mapping
- Neues Template
- Verlinkung von Liste
Models in Templates: View Liste¶
core/views.py
from core.models import Project
def index(request):
#...
project_list = Project.objects.all()
context_dict = {'projects': project_list}
#...
Template¶
core/templates/index.html
{% if projects %}
<ul>
{% for project in projects %}
<li>{{ project.name }}</li>
{% endfor %}
</ul>
{% else %}
<strong>Keine Projekte</strong>
{% endif %}
Model Detailseite: View Detail¶
core/views.py
from django.shortcuts import get_object_or_404
from core.models import Project
from django.template import RequestContext
def project(request, project_id):
project = get_object_or_404(Project, id=project_id)
context_dict = {'project': project}
return render(request, 'project.html', context_dict)
Note
Siehe auch get_list_or_404
Model Detailseite: URL-Mapping¶
core/urls.py
url(r'^project/(?P<project_id>\d+)/$', views.project, name='project'),)
Note
Weitere Beispiele: * (?P<project_name>w+) * (?P<year>d{4}) * (?P<month>[a-z]{3})
Model Detailseite: Template¶
core/templates/project.html
<!DOCTYPE html>
<html>
<head>
<title>Project</title>
</head>
<body>
<h1>{{ project.name }}</h1>
<p>{{ project.copy }}</p>
</body>
</html>
Model URLs Funktion am Model¶
core/models.py
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('project', args=[str(self.id)])
Note
Um Objekte zu referenzieren, ist es sehr hilfreich, die Objekte um Funktionen zu erweitern wie get_absolute_url
.
Verlinkung im Template¶
<a href="{{ project.get_absolute_url }}">{{ project.name }}</a>
Asset Management¶
Wir bauen einen einfachen Bildupload
Asset Management 1¶
Neues Attribut hinzufügen
core/models.py
image = models.ImageField(upload_to='project')
Asset Management 2¶
Settings Überprüfen
portfolio/settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Asset Management 3¶
Template Context Processor setzen für Media damit {{MEDIA_URL}} auch im Template zur Verfügung steht.
portfolio/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'django.template.context_processors.media',
...
],
},
},
]
Asset Management 4¶
portfolio/urls.py
from django.conf.urls.static import static
from django.conf import settings
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Asset Management 5¶
Auf der Detailseite das Bild hinzufügen
core/templates/project.html
<img src="{{ MEDIA_URL }}{{ project.image }}">
Übung: Projekt-Kategorien¶
Kategorieliste mit Projekten darstellen
Forms¶
Form: Checkliste¶
- forms.py erstellen
- ModelForm für Model erstellen
- Update-View erstellen (display, save, errors)
- urls.py updaten
- Template erstellen
forms.py und ModelsForm¶
core/forms.py
from django import forms
from core.models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name']
Note
Man KANN jedes Feld einzeln definieren. Das machen wir aber nicht.
Form: die View Dazu¶
core/views.py
from core.forms import ContactForm
def add_contact(request):
context = RequestContext(request)
if request.method == 'POST':
form = ContactForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print form.errors
else:
form = ContactForm()
return render(request, 'add_contact.html', {'form': form})
Form: Das Template¶
<form id="cform" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Contact Me!" />
</form>
Outro¶
Weitere Informationen¶
Danke¶
Note
Good Bye!
Wie man mich erreichen kann¶
- Privat: s@digitalkultur.net
- S&V: d.schwertel@s-v.de