SlideShare ist ein Scribd-Unternehmen logo
1 von 69
Downloaden Sie, um offline zu lesen
Django in a Nutshell
                            Python User Group München - µPy
                                   6. November 2012

                            juergen.schackmann@gmail.com




© Juergen Schackmann 2012
Ziel

 ▸    Überblick über Django
 ▸    Besprechung wesentlicher Komponenten
 ▸    Customizing Möglichkeiten
 ▸    Django Ökosystem
 ▸    Bewertung


 ▸    Kein Django Tutorial
 ▸    Kein hands-on workshop (gerne als separater Termin)




© Juergen Schackmann 2012                                   2/69
Agenda

 ▸    Übersicht
 ▸    Quick Start
 ▸    Project und (pluggable) Apps
 ▸    Wesentlich Django Komponenten
 ▸    Admin
 ▸    Settings
 ▸    Room for Improvement




© Juergen Schackmann 2012             3/69
Übersicht
Was ist Django (nicht)

 ▸   Web application Framework
 ▸   Pure Python
 ▸   Full-Stack (keine bzw. kaum externe dependencies)
 ▸   Philosophie:
      ▸   Dry
      ▸   Loose Coupling
      ▸   MVC bzw. MVT
 ▸   BSD Lizenz
 ▸   Django Software Foundation
 ▸   Sehr gute Dokumentation und große freundliche Community
 ▸   Django ist kein Content Management System (aber es gibt in Django implementierte
     CMS)


     Quellen: django-workshop.de/einfuehrung.html, djangobook.com/en/2.0/chapter01.html



© Juergen Schackmann 2012                                                                 5/69
Historie

 ▸   Entstanden 2003/2004 bei lawrence.com (Medienunternehmen, Zeitung) als
     closed source in Kansas (ebenso wie memcache)
 ▸   Benannt nach Django Reinhardt (Jazz Guitarist)
 ▸   Open Source: 2005
 ▸   “Benevolent Dictators for Life”: Jacob Kaplan-Moss, Adrian Holovaty
 ▸   Ursprung aus der Medienindustrie hat die Use Cases und Sweet Spots
     geprägt
 ▸   Aktuelle stabile Version: 1.4.2
 ▸   Version 1.5 bringt Python 3 Unterstützung
 ▸   Minor Release alle 9 Monate


Quellen:
http://www.quora.com/What-is-the-history-of-the-Django-web-framework,http://www.djangobook.com/en/2.0/chapter01.html


© Juergen Schackmann 2012                                                                                              6/69
Django Ressourcen

 ▸    Homepage: djangoproject.com
 ▸    Docs: docs.djangoproject.com/en/1.4/
 ▸    Code: github.com/django/django
 ▸    User Mailing List: groups.google.com/forum/?fromgroups#!forum/django-
      users
 ▸    Django App Ökosystem: djangopackages.com
 ▸    Django powered Websites: djangosites.org
 ▸    Django Snipptes: djangosnippets.org




© Juergen Schackmann 2012                                                7/69
Bücher, Tutorials, Trainings, ...

 ▸   Tutorial: docs.djangoproject.com/en/1.4/intro/tutorial01/


 ▸   Django Workshop (deutsch): django-workshop.de


 ▸   Django Book: djangobook.com/en/2.0/index.html


 ▸   amazon.de/Pro-Django-Experts-Voice-
     Development/dp/1430210478


 ▸   amazon.de/Python-Development-Django-Developers-
     Library/dp/0132356139

© Juergen Schackmann 2012                                        8/69
Videos


 ▸    Serie von Django Video Tutorials (für Anfänger):
      hackedexistence.com/project-django.html
 ▸    Video: Django Blog in 30 min (für Fortschreitende):
      http://arunrocks.com/blog/2012/03/05/building_a_bl
      og_in_30_mins_with_django_%28screencast%2
 ▸    Django in Depth, sehr gute 3h presentation (nichts
      für Anfänger): youtube.com/watch?v=t_ziKY1ayCo




© Juergen Schackmann 2012                                  9/69
Bekannte Django Sites

   pinterest.com

                                                       bitbucket.org




                                                  disqus.com
                            instagram.com
      nytimes.com




                              turnkeylinux.org
 washingtonpost.com


                                                 ubuntuusers.de



© Juergen Schackmann 2012                                              10/69
Quick-Start
Quick Start

 1. Django Installation


 2. Projekt erzeugen


 3. Development Web Server starten


 4. App(s) erzeugen


 5. Datenbank Schema erzeugen




© Juergen Schackmann 2012            12/69
Installation

 >>> pip install django


==> Done :-)


 ▸    7,7 MB download vom PyPi
 ▸    keine weiteren Dependencies
 ▸    Tip: am besten Installation in ein Virtualenv




© Juergen Schackmann 2012                             13/69
Projekt erzeugen

Django kommt mit Kommandozeilen Tool zur Erzeugung und Verwaltung von
Projekten und Apps
 >>> django-admin startproject nutshell
 >>> cd nutshell



Erzeugt die komplette Verzeichnisstruktur mit allen relevanten Daten für ein
Django Projekt
 nutshell/
      manage.py                    << Tool zur Verwaltung dieses Projekts
      nutshell/                    << Verzeichnis mit Code & Settings für dieses Projekt
           __init__.py
           settings.py             << Konfigurations File
           urls.py                 << Url Konfiguration
           wsgi.py                 << WSGI Applikation




© Juergen Schackmann 2012                                                                  14/69
Django Webserver starten


Starten des Django Webservers
 >>> python manage.py runserver




Und Aufruf unter http://127.0.0.1:8000/


Achtung: Django Webserver nur für Entwicklung nutzen, nicht für Produktion
vorgesehen




© Juergen Schackmann 2012                                               15/69
App(s) erzeugen

Jedes Django Projekt besteht aus mindestens einer App (in der Regel aber aus
sehr vielen Apps)
 >>> python manage.py startapp nuts



Erzeugt die komplette Verzeichnisstruktur mit allen relevanten Dateien für
eine Django App
 nutshell/                       << Root
      nutshell/                  << Project
      nuts/                      << App Verzeichnis
            __init__.py
            models..py           << App Models
            tests.py             << Unit Tests
            views.py             << Views (=Controllers)



Achtung: Apps müssen nicht im Project Verzeichns liegen, Python Path reicht
aus

© Juergen Schackmann 2012                                                    16/69
Datenbank Schema erzeugen



Generierung des Datenbank Schemas
 >>> python manage.py syncdb




Achtung: zuerst muss in settings.py die Datenbank/ Datenbankverbindung
eingetragen werden (am besten SQLite)




© Juergen Schackmann 2012                                                17/69
Notwendige nächste Schritte

 ▸    Anpassung settings.py
       ▸   Eintrag der Datenbank
       ▸   Hinzufügen gewünschter Apps



      ==> Happy Coding




© Juergen Schackmann 2012                18/69
Project und (pluggable) Apps
Apps im Project (Idealfall)



                    App 1            App 2        App 3          App 4




                     Konfiguration       URL Routing      Presentation
                      Settings.py          urls.py         Templates




 ▸    Project definiert sich über settings.py, urls.py und Templates (Verzeichnis)
 ▸    Project besteht aus unabhängigen Apps
 ▸    Apps müssen nichts übereinander wissen

© Juergen Schackmann 2012                                                      20/69
Pluggable Apps

 ▸     Jede App sollte
        ▸     genau eine Aufgabe sehr gut erledigen
        ▸     eigenständig funktionieren (ohne Wissen über andere Apps)
        ▸     möglichst weit konfigurierbar sein
        ▸     idealer Weise mit eigener setup.py und upload zu pypi
 ▸     Beispiele für gute Apps
        ▸     Tagging
        ▸     Themes/Skins
        ▸     Comments
 ▸     Beispiele for schlechte App:
       “Handle entries in a weblog, and users who post them, and their authentication, and
       tagging and categorization, and some flat pages for static content, and...
 ▸     Übersicht Django Apps: djangopackages.com
Quellen: http://media.b-list.org/presentations/2008/djangocon/reusable_apps.pdf, http://www.slideshare.net/coordt/pluggable-django-application-patterns-pycon-2011




© Juergen Schackmann 2012                                                                                                                                            21/69
Typisches Project Verzeichnis

 ▸    Default Einstellung sind Best Practice für kleinere bis mittlere Projekte
 ▸    Wording ist Konvention und beliebig anpassbar
 ▸    Verzeichnisstruktur mein persönlicher Vorschlag und beliebig anpassbar
 ▸    Konvention und Struktur wird in settings.py definiert


 nutshell/                  << Project Root
      manage.py             << Tool zur Verwaltung dieses Projects(automatisch erzeugt)
      site_static/          << Statische Files (wird während Deployment gefüllt)
      media/                << Media Files (upload files, wird während Nutzung gefüllt)
      nutshell/             << Verzeichnis mit Code & Settings für dieses Projekt
            __init__.py
            settings.py     << Konfigurations File (automatisch erzeugt und erweitert))
            urls.py         << Url Konfiguration (automatisch erzeugt und erweitert)
            wsgi.py         << WSGI Applikation(automatisch erzeugt)
            templates/      << Projektspezifische Templates (überschreiben App Templates)
            fixtures/       << Projektspezifische Fixtures(überschreiben App Fixtures)




© Juergen Schackmann 2012                                                                   22/69
Typisches App Verzeichnis

 ▸    All apps müssen als Package im Python Path auffindbar sein
 ▸    models.py ist die einzige Anforderung von Django, kann aber auch leer sein
 ▸    Wording für "templatetags" und "commands" ist fix
 nuts/                      << App Verzeichnis
         __init__.py
         settings.py        << App spezifische Settings / Konfiguration
         models.py          << App Models
         tests.py           << Unit Tests
         forms.py           << Django Formulare
         admin.py           << Admin (Admin Seiten für ausgewählte Models)
         views.py           << Views (=Controllers)
         urls.py            << Urls Conf (Url mapping auf App Views)
         templatetags/      << Custom templatetags
         command/           << Zusätzliche manage.py. commands
         templates/         << App Templates (durch Project Templates überschreibbar)
         static/            << Statische App files (durch statische Project files überschreibbar)
         fixtures/          << App Fixtures




© Juergen Schackmann 2012                                                                           23/69
Typische Django App Liste (settings.py)

 INSTALLED_APPS = (
   'django.contrib.auth',           << User Management, Authentifizierung, Autorisierung
   'django.contrib.contenttypes',   << Dependency für folgende
   'django.contrib.sessions',       << Session Management
   'django.contrib.sites',          << Betreiben mehrere Sites aus einem Projekt
   'django.contrib.messages',       << Messages im Browser
   'django.contrib.staticfiles',    << Statische files für Entwicklung und Deployment
   'django.contrib.admin',          << Admin für alle apps (sehr nützlich)
   'south',                         << Datenschema Migration
   'debug_toolbar'                  << Debug Toolbar im Browser (für Entwicklung)
   'nuts1',                         << Custom App
   'nuts2',                         << Custom App
 )




© Juergen Schackmann 2012                                                                  24/69
Wesentliche Django
  Komponenten
   (views,templates,models,forms)
Django Http Request (vereinfacht)


                                                     Model

                                                      Model
                                           Control
       Django
                            Url Konfigu-
        HTTP                                 View
                               raiton
       Handler



                                                     Templates



                                                      View




© Juergen Schackmann 2012                                        26/69
Model (ORM)
                                                                 models.py


                                                                  Model



        Django
                            Url Konfigu-
         HTTP                                  View
                               raiton
        Handler



                                                                 Templates




  ▸   Eigener Object-Relational-Mapper
  ▸   Verfügbare Backend Wrapper: SQLite, MySQL, PostgreSQL, Oracle
  ▸   Es werden alle wesentlichen Feldtypen unterstützt sowie 1-1, 1-n und m-n
      Beziehungen
  ▸   Datenbanktyp und Datenbankverbindung wird in settings.py definiert
  ▸   Initiale Erzeugung des Datenbankschemas inkl. Fixtures: manage.py syncdb

© Juergen Schackmann 2012                                                    27/69
Einfaches Model

 class Recipe(models.Model):
    title = models.CharField(verbose_name='Titel', max_length=255)
    preparation = models.TextField('Zubereitung', help_text='Zubereitung der Zutaten',blank=True)
    date_created = models.DateTimeField(editable=False)
    is_active = models.BooleanField('Aktiv')

     def __unicode__(self):
       return self.title




 ▸     Ausreichend für Erzeugung der Datenbankobjekte (syncdb)
 ▸     Verhält sich wie jede Python Class
 ▸     Viel __metaclass__ magic im Hintergrund


© Juergen Schackmann 2012                                                                           28/69
Models Meta

 class Recipe(models.Model):
    ...

     class Meta:
        verbose_name = 'Rezept'
        verbose_name_plural = 'Rezepte'
        ordering = ['-date_created']
        db_table = 'meine_rezepte'




 ▸     In Meta können unterschiedlichste Details konfiguriert werden
 ▸     Übersicht über alle Meta optionen:
       docs.djangoproject.com/en/1.4/ref/models/options/
 ▸     Die vorhandenen Defaults sind aber in der Regel ausreichend


© Juergen Schackmann 2012                                              29/69
Model Beziehungen

 class Category(models.Model):
    name = models.CharField('Name', max_length=100)
    description = models.TextField('Beschreibung', blank=True)

 class Recipe(models.Model):
    …
    categories = models.ManyToManyField(Category,related_name='recipes',verbose_name='Kategorie')
    author = models.ForeignKey(User, verbose_name='Autor') # User ist aus Django Contrib




 ▸   Django unterstützt 1-1, 1-n und m-n Beziehungen
 ▸   Mapping Models für m-n Beziehungen werden automatisch erzeugt oder
     können auch explizit definiert werden
 ▸   Beziehungsfeld im “entfernten” Model wird automatisch angelegt

© Juergen Schackmann 2012                                                                           30/69
Model Methoden

 class Recipe(models.Model):
   @models.permalink
   def get_absolute_url(self): # Empfohlene Methode fuer alle Modelle
      return ('recipes_recipe_detail', (), {'id': self.id})



   def save(self, *args, **kwargs): # Ueberschreiben einer Standard Methode
      if not self.id: # D.h. es handelt sich um eine neue, noch nicht gespeicherte Instanz
        self.date_created = datetime.datetime.now()
      super(Recipe, self).save(*args, **kwargs)



   def is_tasty(self): # Erzeugen einer eigenen Methode für Recipes
      return 'yes'


   @property
   def tasty(self): # Erzeugen einer Property
      return 'yes'


© Juergen Schackmann 2012                                                                    31/69
Model Managers

 class Recipe(models.Model):
    objects = models.Manager() # Default Manager (diese Zeile könnte auch weggelassen werden)
    active = ActiveRecipeManager() # Custom Manager der nur aktive Rezepte zurkückliefert




 ▸    Jedes Model hat mindestens ein Manager object; default Name "objects"
 ▸    Manager besitzt alle notwendigen Methoden, um Models
             ▸   zu verwalten (erzeugen, löschen, etc)
             ▸   Datenbankqueries abzusetzen (select)
 ▸    Manager funktioniert nicht bei Model Instanzen, d.h. nicht um einzelne
      Objecte zu managen.
 ▸    Docs: docs.djangoproject.com/en/dev/topics/db/managers/



© Juergen Schackmann 2012                                                                       32/69
Model QuerySets

 queryset=Recipe.objects.filter(title='abc')




 ▸    Django Abstraktion einer DB query
 ▸    Chainable
 ▸    “lazy”, d.h. Datenkbankzugriff erst dann, wenn unbedingt notwendig
 ▸    Benutzbar wie Python Listen
 ▸    Docs: docs.djangoproject.com/en/dev/ref/models/querysets/




© Juergen Schackmann 2012                                                  33/69
Beispiele Managers und Queries

 recipe=Recipe(title='test') # Neue Recipe Instanz wird erzeugt
 recipe.save() # Speicherung der neuen Instanz in Datenbank


 recipes=Recipe.objects.all() # liefert ein QuerySet zurück, aber noch keine Datenbankabfrage
 for recipe in recipes: # erst jetzt erfolgt die Datenbankabfrage und liefert liste zurück
   ....



 recipes=Recipe.objects.filter(active=True) # liefert QuerySet zurueck, aber noch keine Abfrage
 recipes = recipes.filter(author=user_juergen) # QuerySets lassen sich verketten
 recipe_first=recipes[0] # Erst jetzt erfolgt die Abfrage



 recipe = recipes.objects.get(author__name='juergen') # Beziehungen per '__', get findet genau
                                                                  eine Instance oder erzeugt Fehler
 recipe_first.objects.all() # Fehler, objects funktioniert nicht mit Instanzen




© Juergen Schackmann 2012                                                                             34/69
Model Vererbung

 class Recipe(models.Model):
    ...

 class PremiumRecipe(Recipe):
    price=models.FloatField()




 ▸    Modelle können vererbt werden
 ▸    Im Hintergrund wird 1-1 Beziehung zwischen Parent (Recipe) und Child
      (PremiumRecipe) erzeugt (und automatisch verwaltet)
 ▸    Zu tiefe Vererbung kann deshalb zu Performanceproblemen führen
 ▸    Spezialfälle: abstract, proxy, managed


© Juergen Schackmann 2012                                                    35/69
Templates
                                                                         Model



        Django
                             Url Konfigu-
         HTTP                                      View
                                raiton
        Handler



                                                                        Templates



                                                                        Templates/
 ▸    Eigenes Template System
 ▸    Kann ersetzt werden (bswp jinja)
 ▸    Performance: ok, aber schlechter als jinja


"the Django template system is not simply Python embedded into HTML. This is by design:
the template system is meant to express presentation, not program logic."




© Juergen Schackmann 2012                                                            36/69
Wesentliche Template Elemente

 ▸    Jedes Template wird mit einem Context dict gerendert
 ▸    Nur Objekte aus dem übergebenen Context sind verfügbar
 ▸    Aus Template heraus können nur Funktionen ohne Parameter aufgerufen
      werden, bspw. recipe.objects.all(), aber nicht
      recipe.objects.filter(title='test')
 ▸    Direkter Aufruf von Context Objekten:
                                        {{ user }}
 ▸    Tags sind komplexere Funktionen und Logik:
                            {% if user %} Welcome {% endif %}
 ▸    Filter sind Funktionen die den Input verändern:
                                 {{ user.name|capfirst }}


© Juergen Schackmann 2012                                              37/69
Einfaches Beispiel

 <head><title>Kochbuch</title></head>
 <body>
   <h1>Kochbuch</h1>
   {% if user %}Welcome {{ user.name|capfirst }} {% else %} Login {% endif %}
   <h2>Alle Rezepte</h2>
   <ul>
      {% for recipe in object_list %}
           <li><a href="{{ recipe.get_absolute_url }}">{{ recipe.title }}</a></li>
      {% endfor %}
   </ul>
 </body>




© Juergen Schackmann 2012                                                            38/69
Template Vererbung

 ▸    Templates können einfach vererbt werden per "extends"
 ▸    Mehrfachvererbung ist nicht möglich
 ▸    In einem Templates können Blöcke definiert werden
 ▸    In einem vererbten Template können die Blöcke überschrieben oder
      erweitert werden
 ▸    Mehrfahrvererbung durch "include" simuliert




© Juergen Schackmann 2012                                                39/69
Beispiel Vererbung: base.html

 <head>
      <title>{% block title %}Kochbuch{% endblock%}</title>
 </head>
 <body>
   <h1>Kochbuch</h1>
   {% block login %} {% endblock %}
   {% block content %} {% endblock %}
 </body>




© Juergen Schackmann 2012                                     40/69
Beispiel Vererbung: recipe_list.html

 {% extends "base.html" %}


 {% block title %}{{ block.super }} - Alle Rezepte{% endblock %}



 {% block login %} {% include "userauth/login.html" %} {% endblock %}



 {% block content %}
   <h2>Alle Rezepte</h2>
   <ul>
      {% for recipe in object_list %}
      <li><a href="{{ recipe.get_absolute_url }}">{{ recipe.title }}</a></li>
      {% endfor %}
   </ul>
 {% endblock %}




© Juergen Schackmann 2012                                                       41/69
Templates Finder & Loader

Kein direkter Zugriff auf Template files, nur über Templates Loader (definiert in
settings.py)

TEMPLATE_LOADERS = (
  'django.template.loaders.filesystem.Loader',
  'django.template.loaders.app_directories.Loader',)



 ▸   Loader werden in definierter Reihenfolge abgearbeitet
 ▸   Erster Fund wird zurückgeliefert
 ▸   Default Verhalten:
      ▸   Suche im Project Template Verzeichnis (d.h. gecustomized für Project)
      ▸   Wenn nicht gefunden, suche in den App Template Verzeichnissen aller Apps (in
          der Reihenfolge wie in INSTALLED_APPS) und liefer ersten Fund zurück
      ▸   Apps können sich Templates also auch selbst überschreiben (wichtig für
          Skins/Themes)


© Juergen Schackmann 2012                                                           42/69
Beispiel Finder & Loader

nuts/recipe_list.html extends extends nuts/base.html extends base.html

 nutshell/                                    << Root
       nutshell/                              << Project
               templates/                     << Project Templates
                    base.html                 << Project Base
                    nuts/                     << Project Nuts Templates
                            base.html         << Projet Nuts bass
       nuts/                                  << App Verzeichnis
               templates/                     << App Templates
                    nuts/                     << App Nuts Templates Verzeichnis
                            base.html         << App Nuts Base
                            recipe_list.hml




© Juergen Schackmann 2012                                                         43/69
Views
                                                                            Model
                                                        views.py/

          Django
                                Url Konfigu-
           HTTP                                           View
                                   raiton
          Handler



                                                                           Templates


 ▸   Views sind die Django Controller (MVC)
 ▸   View Anforderungen
      ▸    Callable
      ▸    Parameter: Django request object (plus optionale args,kwargs)
      ▸    Return: Django response object
 ▸   Typische Struktur:
      ▸    Bestimmung Templates
      ▸    Berechnung des Context objects (dict)
      ▸    Rendern des Templates mit Context
      ▸    Return des gerenderten Templates in Django Response object

© Juergen Schackmann 2012                                                              44/69
Einfacher View

def hello(request):
   return HttpResponse("<html><body>Hello World</body></html>")




         Views können implementiert werden ohne Django ORM
                           und Templates!




© Juergen Schackmann 2012                                         45/69
View mit Logik und Shortcuts

def recipe_detail(request, recipe_id):
  try:
     r = Recipe.objects.get(pk=recipe_id)
  except Recipe.DoesNotExist:
     raise Http404
  t = loader.get_template('recipe/recipe_detail.html')
  c = RequestContext(request, {'recipe': r})
  return HttpResponse(t.render(c))



def recipe_detail(request, recipe_id):
   r=get_object_or_404(Recipe, pk=recipe_id)
   return render(request,'recipe/recipe_detail.html', {'recipe': r})




© Juergen Schackmann 2012                                              46/69
Class Based (Generic) Views

class RecipeDetailView(DetailView):
     model=Recipe
     #template_name='recipe/recipe_detail.html' << default



class RecipeListView(ListView):
     model=Recipe
     template_name='recipe/my_recipe_list.html' << default



 ▸     Customizing via
        ▸   __init__ Parameter (ohne neue Klasse)
        ▸   Class Atrribute
        ▸   Methoden überschreiben
 ▸     Methoden überschreiben komplex, derzeit schwache Doku
 ▸     Achtung: class based views haben in UrlConf spezielle Syntax
© Juergen Schackmann 2012                                             47/69
Forms

 ▸   Eigenes Forms Package
      ▸   Initialisierung aus Model
      ▸   Automatisches Rendern in HTML
      ▸   Einfaches umwandlen von Post Request zurück in Model


 ▸   ModelForms
      ▸   Dynamische Generierung aus Model


 ▸   Hilfreiche App: ChrispyForms github.com/maraujop/django-crispy-forms


 ▸   Docs: docs.djangoproject.com/en/1.4/topics/forms



© Juergen Schackmann 2012                                               48/69
Form Handling Beispiel

def edit(request, recipe_id):
   recipe = get_object_or_404(Recipe, pk=recipe_id)
   if request.method == 'POST':
      form = RecipeForm(instance=recipe, data=request.POST)
      if form.is_valid():
           form.save()
           return HttpResponseRedirect(recipe.get_absolute_url())
   else:
      form = RecipeForm(instance=recipe)
   return render(request, 'recipes/form.html',
      {'form': form, 'add': False, 'object': recipe})




© Juergen Schackmann 2012                                           49/69
Url Konfiguration
                                                        Model
                              urls.py/

        Django
                            Url Konfigu-
         HTTP                                View
                               raiton
        Handler



                                                       Templates




 ▸    Mapping Tuple: Regex ==> Views
 ▸    Tuple Name: “urlpatterns”
 ▸    Regex Arguments als args und kwargs für View
 ▸    Named Patterns mit Reverese URL Lookup
 ▸    App Urls pluggable in Project Urls via Include



© Juergen Schackmann 2012                                          50/69
Typische App Url Konfiguration

urlpatterns = patterns('recipes.views',
        url(r'^erstellen/$', 'add', name='recipes_recipe_add'),
        url(r'^bearbeiten/(?P<recipe_id>d+)/$', 'edit', name='recipes_recipe_edit'),
        url(r'^rezept/(?P<pk>[-w]+)/$', RecipeDetailView.as_view(), name='recipes_recipe_detail'),
        url(r'^$', RecipeListView.as_view(), name='recipes_recipe_index'),
)


    ▸     patterns(prefix,*list)
           ▸   Prefix: optional, gemeinsames Package für alle views
    ▸     url(regex,view, kwargs,name)
           ▸   view: view name als string oder callable
           ▸   kwargs (optional): zusätzliche default Parameter
           ▸   name(optional): beliebiger, aber eindeutiger name
    ▸     Weitere Syntaxvarianten möglich; siehe docs:
          docs.djangoproject.com/en/1.4/topics/http/urls/
© Juergen Schackmann 2012                                                                             51/69
Typische Project Url Konfiguration

admin.autodiscover() # ueblich wenn admin verwendet wird



urlpatterns = patterns('',
    url(r'^$', 'recipes.views.home', name='home'),
    url(r'^recipes/', include('recipes.urls')),
    url(r'^admin/', include(admin.site.urls)),
)




    ▸   Vial Include werden Url Konfigurationen ineinander geschachtelt
    ▸   Vorallem App Urls ==> Project Urls
    ▸   Achtung: Url von Apps nicht fix, sondern abhängig von Project ==>
        reverse lookup


© Juergen Schackmann 2012                                                 52/69
Reverse URL Lookup

# in templates mit template tag
{% url recipes_recipe_add %}



# im python code
reverse('recipes_recipe_detail', kwargs={'pk':id})



# via get_absolute_url und permalink decorator
recipe.get_absolute_url()




© Juergen Schackmann 2012                            53/69
Django Http Request Lifecycle




                       Request                                     View
                                           Url Config                                Model
                      Middleware                                Middleware


    Django
     HTTP                                                                    View
    Handler



                               Response                 Exception                   Templates
                              Middleware                Middleware




© Juergen Schackmann 2012                                                                    54/69
Admin
Django.contrib.admin


 ▸    Meistgenutzte Applikation
 ▸    Größter Django Selling Point
 ▸    Hierarchische Struktur
       ▸   Liste aller Apps
       ▸   Liste aller Models je App
       ▸   List und Detail View je Model
 ▸    Dynamische Generierung der Seiten auf Basis der Models
 ▸    Sehr umfangreiches Customizing möglich
 ▸    Unterschiedliche Admin Sites mit unterschiedlichen
      Ausprägungen möglich

© Juergen Schackmann 2012                                      56/69
Admin Beispiel


class RecipeAdmin(admin.ModelAdmin):
   fields = ['title','preparation', 'date_created']


   def get_query_set(self,request):
      return Recipe.objects.filter(active=True)


admin.site.register(Category)
admin.site.register(Recipe, RecipeAdmin)




© Juergen Schackmann 2012                             57/69
Screenshots


 ▸    xxx




© Juergen Schackmann 2012   58/69
Settings
Settings.py

 ▸    Zentrale Konfiguration Django Project
 ▸    Python File
 ▸    100+ Django Settings (mit sinnvollen defaults)
       ▸   Datenbank
       ▸   Apps
       ▸   Template Verzeichnisse
       ▸   Statische Verzeichnisse
       ▸   Middleware
       ▸   Locale, Timezone, …
 ▸    Kann auch for eigene App settings genutzt werden
 ▸    Docs: docs.djangoproject.com/en/1.4/ref/settings/


© Juergen Schackmann 2012                                 60/69
Wichtige Settings Einstellungen


 ▸    DEBUG
 ▸    Datenbank
 ▸    Installed Apps
 ▸    Middleware
 ▸    Context_Processors
 ▸    Statische Verzeichnisse
 ▸    Template Verzeichnisse
 ▸    Timezone
 ▸    Locale


© Juergen Schackmann 2012           61/69
Typische Django App Liste (settings.py)

 INSTALLED_APPS = (
   'django.contrib.auth',           << User Management, Authentifizierung, Autorisierung
   'django.contrib.contenttypes',   << Dependency für folgende
   'django.contrib.sessions',       << Session Management
   'django.contrib.sites',          << Betreiben mehrere Sites aus einem Projekt
   'django.contrib.messages',       << Messages im Browser
   'django.contrib.staticfiles',    << Statische files für Entwicklung und Deployment
   'django.contrib.admin',          << Admin für alle apps (sehr nützlich)
   'south',                         << Datenschema Migration
   'debug_toolbar'                  << Debug Toolbar im Browser (für Entwicklung)
   'nuts1',                         << Custom App
   'nuts2',                         << Custom App
 )




© Juergen Schackmann 2012                                                                  62/69
Typische Settings Komponenten


 ▸    Bestimmung Project Root für generische Verweise auf
      Verzeichnisse
PROJECT_ROOT = dir(abspath(__file__)) # Kann ff für Verzeichnisdefinition verwendet werden


TEMPLATE_DIRS=(join(PROJECT_ROOT,'templates'))




 ▸    Definition von settings in Abhängigkeit von Debug setting
if DEBUG:
     ….




© Juergen Schackmann 2012                                                                    63/69
Settings in komplexen Umgebungen


 ▸      Verteilung settings auf verschiedenen files
        ▸   Unterschiedliche Settings Files für unterschiedliche
            Umgebungen
        ▸   Import files in “master” settings file in Abhängigkeit von
            bestimmten Bedingungen
import common_settings


if environ('DJANGO_ENVIRONMENT')=='DEV':
   import dev_settings
else:
   import prod_settings


try:
   import local_settings
except:
   pass

© Juergen Schackmann 2012                                                64/69
Zugriff auf Settings und App Settings


 ▸    Zugriff auf settings via django.conf.settings object
       ▸   Django Default Settings
       ▸   Project Settings
       ▸   Lazy Loading
 ▸    In settings.py sind nicht nur Django Core Settings erlaubt
 ▸    Jede App kann eigene settings definieren und nutzen

from django.conf import settings


NUTS_MY_SETTING =settings.get('NUTS_MY_SETTING','My_Default')




© Juergen Schackmann 2012                                          65/69
Room for Improvement?
Pro Django


 ▸    Sehr flache Lernkurve
 ▸    Genügend Flexibilität bei komplexen Anforderungen
 ▸    Modulares Gesamtkonzept
 ▸    Sehr großes App Ökosystem
 ▸    Große Community und nachhaltige Entwicklung




© Juergen Schackmann 2012                                 67/69
“Batteries Included”


 ▸    Admin
 ▸    Session Handling
 ▸    User Management, Authentifizeirung, Authorisierung,
      Permissions
 ▸    Comments
 ▸    Tags
 ▸    Static Files
 ▸    Content Types
 ▸    Internationalisierung, Lokalisierung
 ▸    Caching

© Juergen Schackmann 2012                                   68/69
Room for Improvement

 ▸    Convention sehr liberal
 ▸    Pluggable != Pluggable
 ▸    Viele Apps für das selbe Problem
 ▸    Qualität der Apps sehr unterschiedlich
 ▸    Fehlende Contrib Apps:
       ▸   Workflow
       ▸   Object Permissions
       ▸   Schema Migration
 ▸    Python 3 support für apps


© Juergen Schackmann 2012                      69/69

Weitere ähnliche Inhalte

Was ist angesagt?

Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to DjangoKnoldus Inc.
 
Django for Beginners
Django for BeginnersDjango for Beginners
Django for BeginnersJason Davies
 
What is Python Lambda Function? Python Tutorial | Edureka
What is Python Lambda Function? Python Tutorial | EdurekaWhat is Python Lambda Function? Python Tutorial | Edureka
What is Python Lambda Function? Python Tutorial | EdurekaEdureka!
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2fishwarter
 
Python Course | Python Programming | Python Tutorial | Python Training | Edureka
Python Course | Python Programming | Python Tutorial | Python Training | EdurekaPython Course | Python Programming | Python Tutorial | Python Training | Edureka
Python Course | Python Programming | Python Tutorial | Python Training | EdurekaEdureka!
 
Introduction to django framework
Introduction to django frameworkIntroduction to django framework
Introduction to django frameworkKnoldus Inc.
 
Introduzione ad angular 7/8
Introduzione ad angular 7/8Introduzione ad angular 7/8
Introduzione ad angular 7/8Valerio Radice
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOPDzmitry Naskou
 
Spring - Part 2 - Autowiring, Annotations, Java based Configuration - slides
Spring - Part 2 - Autowiring, Annotations, Java based Configuration - slidesSpring - Part 2 - Autowiring, Annotations, Java based Configuration - slides
Spring - Part 2 - Autowiring, Annotations, Java based Configuration - slidesHitesh-Java
 

Was ist angesagt? (20)

django
djangodjango
django
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
Django
DjangoDjango
Django
 
Maven tutorial
Maven tutorialMaven tutorial
Maven tutorial
 
Django for Beginners
Django for BeginnersDjango for Beginners
Django for Beginners
 
Spring mvc
Spring mvcSpring mvc
Spring mvc
 
What is Python Lambda Function? Python Tutorial | Edureka
What is Python Lambda Function? Python Tutorial | EdurekaWhat is Python Lambda Function? Python Tutorial | Edureka
What is Python Lambda Function? Python Tutorial | Edureka
 
Django
DjangoDjango
Django
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
Spring data jpa
Spring data jpaSpring data jpa
Spring data jpa
 
Django
DjangoDjango
Django
 
Splunk 교육자료 v1.2
Splunk 교육자료 v1.2Splunk 교육자료 v1.2
Splunk 교육자료 v1.2
 
Pandas
PandasPandas
Pandas
 
Python Course | Python Programming | Python Tutorial | Python Training | Edureka
Python Course | Python Programming | Python Tutorial | Python Training | EdurekaPython Course | Python Programming | Python Tutorial | Python Training | Edureka
Python Course | Python Programming | Python Tutorial | Python Training | Edureka
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Introduction to django framework
Introduction to django frameworkIntroduction to django framework
Introduction to django framework
 
Django PPT.pptx
Django PPT.pptxDjango PPT.pptx
Django PPT.pptx
 
Introduzione ad angular 7/8
Introduzione ad angular 7/8Introduzione ad angular 7/8
Introduzione ad angular 7/8
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
Spring - Part 2 - Autowiring, Annotations, Java based Configuration - slides
Spring - Part 2 - Autowiring, Annotations, Java based Configuration - slidesSpring - Part 2 - Autowiring, Annotations, Java based Configuration - slides
Spring - Part 2 - Autowiring, Annotations, Java based Configuration - slides
 

Ähnlich wie Django nutshell overview

Schlangenhochzeit in-der Wolke - Pyramid auf Google Appengine
Schlangenhochzeit in-der Wolke - Pyramid auf Google AppengineSchlangenhochzeit in-der Wolke - Pyramid auf Google Appengine
Schlangenhochzeit in-der Wolke - Pyramid auf Google AppengineJens Klein
 
Ueberlegungen Projektmanagement Web Applications
Ueberlegungen Projektmanagement Web ApplicationsUeberlegungen Projektmanagement Web Applications
Ueberlegungen Projektmanagement Web ApplicationsGünther Haslbeck
 
Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)Joachim Baumann
 
Drupal 7 - Media Modul (Version 2.x-dev)
Drupal 7 - Media Modul (Version 2.x-dev)Drupal 7 - Media Modul (Version 2.x-dev)
Drupal 7 - Media Modul (Version 2.x-dev)Steffen Rühlmann
 
Software Entwicklung im Team
Software Entwicklung im TeamSoftware Entwicklung im Team
Software Entwicklung im Teambrandts
 
Drupal Basics (7-8) Vortrag (01.2016)
Drupal Basics (7-8) Vortrag (01.2016)Drupal Basics (7-8) Vortrag (01.2016)
Drupal Basics (7-8) Vortrag (01.2016)Peter_Majmesku
 
Ionic 2 - Hybridapps auf Steroiden
Ionic 2 - Hybridapps auf SteroidenIonic 2 - Hybridapps auf Steroiden
Ionic 2 - Hybridapps auf SteroidenHendrik Lösch
 
Dnug 112014 modernization_openn_ntf_ersatzsession
Dnug 112014 modernization_openn_ntf_ersatzsessionDnug 112014 modernization_openn_ntf_ersatzsession
Dnug 112014 modernization_openn_ntf_ersatzsessionOliver Busse
 
Nagios Conference 2007 | Pluginprogrammierung in Perl by Wolfgang Barth
Nagios Conference 2007 |  Pluginprogrammierung in Perl by Wolfgang BarthNagios Conference 2007 |  Pluginprogrammierung in Perl by Wolfgang Barth
Nagios Conference 2007 | Pluginprogrammierung in Perl by Wolfgang BarthNETWAYS
 
Automatischer Build mit Maven - OPITZ CONSULTING - Stefan Scheidt
Automatischer Build mit Maven - OPITZ CONSULTING - Stefan ScheidtAutomatischer Build mit Maven - OPITZ CONSULTING - Stefan Scheidt
Automatischer Build mit Maven - OPITZ CONSULTING - Stefan ScheidtOPITZ CONSULTING Deutschland
 
Die wichtigsten Technologien für die Entwicklung von Webanwendungen
Die wichtigsten Technologien für die Entwicklung von WebanwendungenDie wichtigsten Technologien für die Entwicklung von Webanwendungen
Die wichtigsten Technologien für die Entwicklung von WebanwendungenYUHIRO
 
Gewinnung von OPEN SOURCE Techniken für junge Unternehmen
Gewinnung von OPEN SOURCE Techniken für junge UnternehmenGewinnung von OPEN SOURCE Techniken für junge Unternehmen
Gewinnung von OPEN SOURCE Techniken für junge UnternehmenBjoern Reinhold
 
Der Django-Admin-Bereich im Überblick
Der Django-Admin-Bereich im ÜberblickDer Django-Admin-Bereich im Überblick
Der Django-Admin-Bereich im ÜberblickAndi Albrecht
 
Applikationsmodernisierung: Der Weg von Legacy in die Cloud
Applikationsmodernisierung: Der Weg von Legacy in die CloudApplikationsmodernisierung: Der Weg von Legacy in die Cloud
Applikationsmodernisierung: Der Weg von Legacy in die CloudAarno Aukia
 
jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen
 jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen
jBPM und Drools: Prozess- und Regelgestützte Fachanwendungengedoplan
 
Ag webmakerimmlab14-sammlungsdoc
Ag webmakerimmlab14-sammlungsdocAg webmakerimmlab14-sammlungsdoc
Ag webmakerimmlab14-sammlungsdocMakergallery
 

Ähnlich wie Django nutshell overview (20)

Schlangenhochzeit in-der Wolke - Pyramid auf Google Appengine
Schlangenhochzeit in-der Wolke - Pyramid auf Google AppengineSchlangenhochzeit in-der Wolke - Pyramid auf Google Appengine
Schlangenhochzeit in-der Wolke - Pyramid auf Google Appengine
 
Ueberlegungen Projektmanagement Web Applications
Ueberlegungen Projektmanagement Web ApplicationsUeberlegungen Projektmanagement Web Applications
Ueberlegungen Projektmanagement Web Applications
 
Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)
 
Web-Tools für das Studium
Web-Tools für das StudiumWeb-Tools für das Studium
Web-Tools für das Studium
 
Webtools studium
Webtools studiumWebtools studium
Webtools studium
 
Drupal 7 - Media Modul (Version 2.x-dev)
Drupal 7 - Media Modul (Version 2.x-dev)Drupal 7 - Media Modul (Version 2.x-dev)
Drupal 7 - Media Modul (Version 2.x-dev)
 
Software Entwicklung im Team
Software Entwicklung im TeamSoftware Entwicklung im Team
Software Entwicklung im Team
 
Agiles Testen - Überblick
Agiles Testen - ÜberblickAgiles Testen - Überblick
Agiles Testen - Überblick
 
Drupal Basics (7-8) Vortrag (01.2016)
Drupal Basics (7-8) Vortrag (01.2016)Drupal Basics (7-8) Vortrag (01.2016)
Drupal Basics (7-8) Vortrag (01.2016)
 
Ionic 2 - Hybridapps auf Steroiden
Ionic 2 - Hybridapps auf SteroidenIonic 2 - Hybridapps auf Steroiden
Ionic 2 - Hybridapps auf Steroiden
 
Dnug 112014 modernization_openn_ntf_ersatzsession
Dnug 112014 modernization_openn_ntf_ersatzsessionDnug 112014 modernization_openn_ntf_ersatzsession
Dnug 112014 modernization_openn_ntf_ersatzsession
 
Nagios Conference 2007 | Pluginprogrammierung in Perl by Wolfgang Barth
Nagios Conference 2007 |  Pluginprogrammierung in Perl by Wolfgang BarthNagios Conference 2007 |  Pluginprogrammierung in Perl by Wolfgang Barth
Nagios Conference 2007 | Pluginprogrammierung in Perl by Wolfgang Barth
 
Automatischer Build mit Maven - OPITZ CONSULTING - Stefan Scheidt
Automatischer Build mit Maven - OPITZ CONSULTING - Stefan ScheidtAutomatischer Build mit Maven - OPITZ CONSULTING - Stefan Scheidt
Automatischer Build mit Maven - OPITZ CONSULTING - Stefan Scheidt
 
Die wichtigsten Technologien für die Entwicklung von Webanwendungen
Die wichtigsten Technologien für die Entwicklung von WebanwendungenDie wichtigsten Technologien für die Entwicklung von Webanwendungen
Die wichtigsten Technologien für die Entwicklung von Webanwendungen
 
Gewinnung von OPEN SOURCE Techniken für junge Unternehmen
Gewinnung von OPEN SOURCE Techniken für junge UnternehmenGewinnung von OPEN SOURCE Techniken für junge Unternehmen
Gewinnung von OPEN SOURCE Techniken für junge Unternehmen
 
Der Django-Admin-Bereich im Überblick
Der Django-Admin-Bereich im ÜberblickDer Django-Admin-Bereich im Überblick
Der Django-Admin-Bereich im Überblick
 
Test-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetpro
Test-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetproTest-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetpro
Test-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetpro
 
Applikationsmodernisierung: Der Weg von Legacy in die Cloud
Applikationsmodernisierung: Der Weg von Legacy in die CloudApplikationsmodernisierung: Der Weg von Legacy in die Cloud
Applikationsmodernisierung: Der Weg von Legacy in die Cloud
 
jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen
 jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen
jBPM und Drools: Prozess- und Regelgestützte Fachanwendungen
 
Ag webmakerimmlab14-sammlungsdoc
Ag webmakerimmlab14-sammlungsdocAg webmakerimmlab14-sammlungsdoc
Ag webmakerimmlab14-sammlungsdoc
 

Django nutshell overview

  • 1. Django in a Nutshell Python User Group München - µPy 6. November 2012 juergen.schackmann@gmail.com © Juergen Schackmann 2012
  • 2. Ziel ▸ Überblick über Django ▸ Besprechung wesentlicher Komponenten ▸ Customizing Möglichkeiten ▸ Django Ökosystem ▸ Bewertung ▸ Kein Django Tutorial ▸ Kein hands-on workshop (gerne als separater Termin) © Juergen Schackmann 2012 2/69
  • 3. Agenda ▸ Übersicht ▸ Quick Start ▸ Project und (pluggable) Apps ▸ Wesentlich Django Komponenten ▸ Admin ▸ Settings ▸ Room for Improvement © Juergen Schackmann 2012 3/69
  • 5. Was ist Django (nicht) ▸ Web application Framework ▸ Pure Python ▸ Full-Stack (keine bzw. kaum externe dependencies) ▸ Philosophie: ▸ Dry ▸ Loose Coupling ▸ MVC bzw. MVT ▸ BSD Lizenz ▸ Django Software Foundation ▸ Sehr gute Dokumentation und große freundliche Community ▸ Django ist kein Content Management System (aber es gibt in Django implementierte CMS) Quellen: django-workshop.de/einfuehrung.html, djangobook.com/en/2.0/chapter01.html © Juergen Schackmann 2012 5/69
  • 6. Historie ▸ Entstanden 2003/2004 bei lawrence.com (Medienunternehmen, Zeitung) als closed source in Kansas (ebenso wie memcache) ▸ Benannt nach Django Reinhardt (Jazz Guitarist) ▸ Open Source: 2005 ▸ “Benevolent Dictators for Life”: Jacob Kaplan-Moss, Adrian Holovaty ▸ Ursprung aus der Medienindustrie hat die Use Cases und Sweet Spots geprägt ▸ Aktuelle stabile Version: 1.4.2 ▸ Version 1.5 bringt Python 3 Unterstützung ▸ Minor Release alle 9 Monate Quellen: http://www.quora.com/What-is-the-history-of-the-Django-web-framework,http://www.djangobook.com/en/2.0/chapter01.html © Juergen Schackmann 2012 6/69
  • 7. Django Ressourcen ▸ Homepage: djangoproject.com ▸ Docs: docs.djangoproject.com/en/1.4/ ▸ Code: github.com/django/django ▸ User Mailing List: groups.google.com/forum/?fromgroups#!forum/django- users ▸ Django App Ökosystem: djangopackages.com ▸ Django powered Websites: djangosites.org ▸ Django Snipptes: djangosnippets.org © Juergen Schackmann 2012 7/69
  • 8. Bücher, Tutorials, Trainings, ... ▸ Tutorial: docs.djangoproject.com/en/1.4/intro/tutorial01/ ▸ Django Workshop (deutsch): django-workshop.de ▸ Django Book: djangobook.com/en/2.0/index.html ▸ amazon.de/Pro-Django-Experts-Voice- Development/dp/1430210478 ▸ amazon.de/Python-Development-Django-Developers- Library/dp/0132356139 © Juergen Schackmann 2012 8/69
  • 9. Videos ▸ Serie von Django Video Tutorials (für Anfänger): hackedexistence.com/project-django.html ▸ Video: Django Blog in 30 min (für Fortschreitende): http://arunrocks.com/blog/2012/03/05/building_a_bl og_in_30_mins_with_django_%28screencast%2 ▸ Django in Depth, sehr gute 3h presentation (nichts für Anfänger): youtube.com/watch?v=t_ziKY1ayCo © Juergen Schackmann 2012 9/69
  • 10. Bekannte Django Sites pinterest.com bitbucket.org disqus.com instagram.com nytimes.com turnkeylinux.org washingtonpost.com ubuntuusers.de © Juergen Schackmann 2012 10/69
  • 12. Quick Start 1. Django Installation 2. Projekt erzeugen 3. Development Web Server starten 4. App(s) erzeugen 5. Datenbank Schema erzeugen © Juergen Schackmann 2012 12/69
  • 13. Installation >>> pip install django ==> Done :-) ▸ 7,7 MB download vom PyPi ▸ keine weiteren Dependencies ▸ Tip: am besten Installation in ein Virtualenv © Juergen Schackmann 2012 13/69
  • 14. Projekt erzeugen Django kommt mit Kommandozeilen Tool zur Erzeugung und Verwaltung von Projekten und Apps >>> django-admin startproject nutshell >>> cd nutshell Erzeugt die komplette Verzeichnisstruktur mit allen relevanten Daten für ein Django Projekt nutshell/ manage.py << Tool zur Verwaltung dieses Projekts nutshell/ << Verzeichnis mit Code & Settings für dieses Projekt __init__.py settings.py << Konfigurations File urls.py << Url Konfiguration wsgi.py << WSGI Applikation © Juergen Schackmann 2012 14/69
  • 15. Django Webserver starten Starten des Django Webservers >>> python manage.py runserver Und Aufruf unter http://127.0.0.1:8000/ Achtung: Django Webserver nur für Entwicklung nutzen, nicht für Produktion vorgesehen © Juergen Schackmann 2012 15/69
  • 16. App(s) erzeugen Jedes Django Projekt besteht aus mindestens einer App (in der Regel aber aus sehr vielen Apps) >>> python manage.py startapp nuts Erzeugt die komplette Verzeichnisstruktur mit allen relevanten Dateien für eine Django App nutshell/ << Root nutshell/ << Project nuts/ << App Verzeichnis __init__.py models..py << App Models tests.py << Unit Tests views.py << Views (=Controllers) Achtung: Apps müssen nicht im Project Verzeichns liegen, Python Path reicht aus © Juergen Schackmann 2012 16/69
  • 17. Datenbank Schema erzeugen Generierung des Datenbank Schemas >>> python manage.py syncdb Achtung: zuerst muss in settings.py die Datenbank/ Datenbankverbindung eingetragen werden (am besten SQLite) © Juergen Schackmann 2012 17/69
  • 18. Notwendige nächste Schritte ▸ Anpassung settings.py ▸ Eintrag der Datenbank ▸ Hinzufügen gewünschter Apps ==> Happy Coding © Juergen Schackmann 2012 18/69
  • 20. Apps im Project (Idealfall) App 1 App 2 App 3 App 4 Konfiguration URL Routing Presentation Settings.py urls.py Templates ▸ Project definiert sich über settings.py, urls.py und Templates (Verzeichnis) ▸ Project besteht aus unabhängigen Apps ▸ Apps müssen nichts übereinander wissen © Juergen Schackmann 2012 20/69
  • 21. Pluggable Apps ▸ Jede App sollte ▸ genau eine Aufgabe sehr gut erledigen ▸ eigenständig funktionieren (ohne Wissen über andere Apps) ▸ möglichst weit konfigurierbar sein ▸ idealer Weise mit eigener setup.py und upload zu pypi ▸ Beispiele für gute Apps ▸ Tagging ▸ Themes/Skins ▸ Comments ▸ Beispiele for schlechte App: “Handle entries in a weblog, and users who post them, and their authentication, and tagging and categorization, and some flat pages for static content, and... ▸ Übersicht Django Apps: djangopackages.com Quellen: http://media.b-list.org/presentations/2008/djangocon/reusable_apps.pdf, http://www.slideshare.net/coordt/pluggable-django-application-patterns-pycon-2011 © Juergen Schackmann 2012 21/69
  • 22. Typisches Project Verzeichnis ▸ Default Einstellung sind Best Practice für kleinere bis mittlere Projekte ▸ Wording ist Konvention und beliebig anpassbar ▸ Verzeichnisstruktur mein persönlicher Vorschlag und beliebig anpassbar ▸ Konvention und Struktur wird in settings.py definiert nutshell/ << Project Root manage.py << Tool zur Verwaltung dieses Projects(automatisch erzeugt) site_static/ << Statische Files (wird während Deployment gefüllt) media/ << Media Files (upload files, wird während Nutzung gefüllt) nutshell/ << Verzeichnis mit Code & Settings für dieses Projekt __init__.py settings.py << Konfigurations File (automatisch erzeugt und erweitert)) urls.py << Url Konfiguration (automatisch erzeugt und erweitert) wsgi.py << WSGI Applikation(automatisch erzeugt) templates/ << Projektspezifische Templates (überschreiben App Templates) fixtures/ << Projektspezifische Fixtures(überschreiben App Fixtures) © Juergen Schackmann 2012 22/69
  • 23. Typisches App Verzeichnis ▸ All apps müssen als Package im Python Path auffindbar sein ▸ models.py ist die einzige Anforderung von Django, kann aber auch leer sein ▸ Wording für "templatetags" und "commands" ist fix nuts/ << App Verzeichnis __init__.py settings.py << App spezifische Settings / Konfiguration models.py << App Models tests.py << Unit Tests forms.py << Django Formulare admin.py << Admin (Admin Seiten für ausgewählte Models) views.py << Views (=Controllers) urls.py << Urls Conf (Url mapping auf App Views) templatetags/ << Custom templatetags command/ << Zusätzliche manage.py. commands templates/ << App Templates (durch Project Templates überschreibbar) static/ << Statische App files (durch statische Project files überschreibbar) fixtures/ << App Fixtures © Juergen Schackmann 2012 23/69
  • 24. Typische Django App Liste (settings.py) INSTALLED_APPS = ( 'django.contrib.auth', << User Management, Authentifizierung, Autorisierung 'django.contrib.contenttypes', << Dependency für folgende 'django.contrib.sessions', << Session Management 'django.contrib.sites', << Betreiben mehrere Sites aus einem Projekt 'django.contrib.messages', << Messages im Browser 'django.contrib.staticfiles', << Statische files für Entwicklung und Deployment 'django.contrib.admin', << Admin für alle apps (sehr nützlich) 'south', << Datenschema Migration 'debug_toolbar' << Debug Toolbar im Browser (für Entwicklung) 'nuts1', << Custom App 'nuts2', << Custom App ) © Juergen Schackmann 2012 24/69
  • 25. Wesentliche Django Komponenten (views,templates,models,forms)
  • 26. Django Http Request (vereinfacht) Model Model Control Django Url Konfigu- HTTP View raiton Handler Templates View © Juergen Schackmann 2012 26/69
  • 27. Model (ORM) models.py Model Django Url Konfigu- HTTP View raiton Handler Templates ▸ Eigener Object-Relational-Mapper ▸ Verfügbare Backend Wrapper: SQLite, MySQL, PostgreSQL, Oracle ▸ Es werden alle wesentlichen Feldtypen unterstützt sowie 1-1, 1-n und m-n Beziehungen ▸ Datenbanktyp und Datenbankverbindung wird in settings.py definiert ▸ Initiale Erzeugung des Datenbankschemas inkl. Fixtures: manage.py syncdb © Juergen Schackmann 2012 27/69
  • 28. Einfaches Model class Recipe(models.Model): title = models.CharField(verbose_name='Titel', max_length=255) preparation = models.TextField('Zubereitung', help_text='Zubereitung der Zutaten',blank=True) date_created = models.DateTimeField(editable=False) is_active = models.BooleanField('Aktiv') def __unicode__(self): return self.title ▸ Ausreichend für Erzeugung der Datenbankobjekte (syncdb) ▸ Verhält sich wie jede Python Class ▸ Viel __metaclass__ magic im Hintergrund © Juergen Schackmann 2012 28/69
  • 29. Models Meta class Recipe(models.Model): ... class Meta: verbose_name = 'Rezept' verbose_name_plural = 'Rezepte' ordering = ['-date_created'] db_table = 'meine_rezepte' ▸ In Meta können unterschiedlichste Details konfiguriert werden ▸ Übersicht über alle Meta optionen: docs.djangoproject.com/en/1.4/ref/models/options/ ▸ Die vorhandenen Defaults sind aber in der Regel ausreichend © Juergen Schackmann 2012 29/69
  • 30. Model Beziehungen class Category(models.Model): name = models.CharField('Name', max_length=100) description = models.TextField('Beschreibung', blank=True) class Recipe(models.Model): … categories = models.ManyToManyField(Category,related_name='recipes',verbose_name='Kategorie') author = models.ForeignKey(User, verbose_name='Autor') # User ist aus Django Contrib ▸ Django unterstützt 1-1, 1-n und m-n Beziehungen ▸ Mapping Models für m-n Beziehungen werden automatisch erzeugt oder können auch explizit definiert werden ▸ Beziehungsfeld im “entfernten” Model wird automatisch angelegt © Juergen Schackmann 2012 30/69
  • 31. Model Methoden class Recipe(models.Model): @models.permalink def get_absolute_url(self): # Empfohlene Methode fuer alle Modelle return ('recipes_recipe_detail', (), {'id': self.id}) def save(self, *args, **kwargs): # Ueberschreiben einer Standard Methode if not self.id: # D.h. es handelt sich um eine neue, noch nicht gespeicherte Instanz self.date_created = datetime.datetime.now() super(Recipe, self).save(*args, **kwargs) def is_tasty(self): # Erzeugen einer eigenen Methode für Recipes return 'yes' @property def tasty(self): # Erzeugen einer Property return 'yes' © Juergen Schackmann 2012 31/69
  • 32. Model Managers class Recipe(models.Model): objects = models.Manager() # Default Manager (diese Zeile könnte auch weggelassen werden) active = ActiveRecipeManager() # Custom Manager der nur aktive Rezepte zurkückliefert ▸ Jedes Model hat mindestens ein Manager object; default Name "objects" ▸ Manager besitzt alle notwendigen Methoden, um Models ▸ zu verwalten (erzeugen, löschen, etc) ▸ Datenbankqueries abzusetzen (select) ▸ Manager funktioniert nicht bei Model Instanzen, d.h. nicht um einzelne Objecte zu managen. ▸ Docs: docs.djangoproject.com/en/dev/topics/db/managers/ © Juergen Schackmann 2012 32/69
  • 33. Model QuerySets queryset=Recipe.objects.filter(title='abc') ▸ Django Abstraktion einer DB query ▸ Chainable ▸ “lazy”, d.h. Datenkbankzugriff erst dann, wenn unbedingt notwendig ▸ Benutzbar wie Python Listen ▸ Docs: docs.djangoproject.com/en/dev/ref/models/querysets/ © Juergen Schackmann 2012 33/69
  • 34. Beispiele Managers und Queries recipe=Recipe(title='test') # Neue Recipe Instanz wird erzeugt recipe.save() # Speicherung der neuen Instanz in Datenbank recipes=Recipe.objects.all() # liefert ein QuerySet zurück, aber noch keine Datenbankabfrage for recipe in recipes: # erst jetzt erfolgt die Datenbankabfrage und liefert liste zurück .... recipes=Recipe.objects.filter(active=True) # liefert QuerySet zurueck, aber noch keine Abfrage recipes = recipes.filter(author=user_juergen) # QuerySets lassen sich verketten recipe_first=recipes[0] # Erst jetzt erfolgt die Abfrage recipe = recipes.objects.get(author__name='juergen') # Beziehungen per '__', get findet genau eine Instance oder erzeugt Fehler recipe_first.objects.all() # Fehler, objects funktioniert nicht mit Instanzen © Juergen Schackmann 2012 34/69
  • 35. Model Vererbung class Recipe(models.Model): ... class PremiumRecipe(Recipe): price=models.FloatField() ▸ Modelle können vererbt werden ▸ Im Hintergrund wird 1-1 Beziehung zwischen Parent (Recipe) und Child (PremiumRecipe) erzeugt (und automatisch verwaltet) ▸ Zu tiefe Vererbung kann deshalb zu Performanceproblemen führen ▸ Spezialfälle: abstract, proxy, managed © Juergen Schackmann 2012 35/69
  • 36. Templates Model Django Url Konfigu- HTTP View raiton Handler Templates Templates/ ▸ Eigenes Template System ▸ Kann ersetzt werden (bswp jinja) ▸ Performance: ok, aber schlechter als jinja "the Django template system is not simply Python embedded into HTML. This is by design: the template system is meant to express presentation, not program logic." © Juergen Schackmann 2012 36/69
  • 37. Wesentliche Template Elemente ▸ Jedes Template wird mit einem Context dict gerendert ▸ Nur Objekte aus dem übergebenen Context sind verfügbar ▸ Aus Template heraus können nur Funktionen ohne Parameter aufgerufen werden, bspw. recipe.objects.all(), aber nicht recipe.objects.filter(title='test') ▸ Direkter Aufruf von Context Objekten: {{ user }} ▸ Tags sind komplexere Funktionen und Logik: {% if user %} Welcome {% endif %} ▸ Filter sind Funktionen die den Input verändern: {{ user.name|capfirst }} © Juergen Schackmann 2012 37/69
  • 38. Einfaches Beispiel <head><title>Kochbuch</title></head> <body> <h1>Kochbuch</h1> {% if user %}Welcome {{ user.name|capfirst }} {% else %} Login {% endif %} <h2>Alle Rezepte</h2> <ul> {% for recipe in object_list %} <li><a href="{{ recipe.get_absolute_url }}">{{ recipe.title }}</a></li> {% endfor %} </ul> </body> © Juergen Schackmann 2012 38/69
  • 39. Template Vererbung ▸ Templates können einfach vererbt werden per "extends" ▸ Mehrfachvererbung ist nicht möglich ▸ In einem Templates können Blöcke definiert werden ▸ In einem vererbten Template können die Blöcke überschrieben oder erweitert werden ▸ Mehrfahrvererbung durch "include" simuliert © Juergen Schackmann 2012 39/69
  • 40. Beispiel Vererbung: base.html <head> <title>{% block title %}Kochbuch{% endblock%}</title> </head> <body> <h1>Kochbuch</h1> {% block login %} {% endblock %} {% block content %} {% endblock %} </body> © Juergen Schackmann 2012 40/69
  • 41. Beispiel Vererbung: recipe_list.html {% extends "base.html" %} {% block title %}{{ block.super }} - Alle Rezepte{% endblock %} {% block login %} {% include "userauth/login.html" %} {% endblock %} {% block content %} <h2>Alle Rezepte</h2> <ul> {% for recipe in object_list %} <li><a href="{{ recipe.get_absolute_url }}">{{ recipe.title }}</a></li> {% endfor %} </ul> {% endblock %} © Juergen Schackmann 2012 41/69
  • 42. Templates Finder & Loader Kein direkter Zugriff auf Template files, nur über Templates Loader (definiert in settings.py) TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader',) ▸ Loader werden in definierter Reihenfolge abgearbeitet ▸ Erster Fund wird zurückgeliefert ▸ Default Verhalten: ▸ Suche im Project Template Verzeichnis (d.h. gecustomized für Project) ▸ Wenn nicht gefunden, suche in den App Template Verzeichnissen aller Apps (in der Reihenfolge wie in INSTALLED_APPS) und liefer ersten Fund zurück ▸ Apps können sich Templates also auch selbst überschreiben (wichtig für Skins/Themes) © Juergen Schackmann 2012 42/69
  • 43. Beispiel Finder & Loader nuts/recipe_list.html extends extends nuts/base.html extends base.html nutshell/ << Root nutshell/ << Project templates/ << Project Templates base.html << Project Base nuts/ << Project Nuts Templates base.html << Projet Nuts bass nuts/ << App Verzeichnis templates/ << App Templates nuts/ << App Nuts Templates Verzeichnis base.html << App Nuts Base recipe_list.hml © Juergen Schackmann 2012 43/69
  • 44. Views Model views.py/ Django Url Konfigu- HTTP View raiton Handler Templates ▸ Views sind die Django Controller (MVC) ▸ View Anforderungen ▸ Callable ▸ Parameter: Django request object (plus optionale args,kwargs) ▸ Return: Django response object ▸ Typische Struktur: ▸ Bestimmung Templates ▸ Berechnung des Context objects (dict) ▸ Rendern des Templates mit Context ▸ Return des gerenderten Templates in Django Response object © Juergen Schackmann 2012 44/69
  • 45. Einfacher View def hello(request): return HttpResponse("<html><body>Hello World</body></html>") Views können implementiert werden ohne Django ORM und Templates! © Juergen Schackmann 2012 45/69
  • 46. View mit Logik und Shortcuts def recipe_detail(request, recipe_id): try: r = Recipe.objects.get(pk=recipe_id) except Recipe.DoesNotExist: raise Http404 t = loader.get_template('recipe/recipe_detail.html') c = RequestContext(request, {'recipe': r}) return HttpResponse(t.render(c)) def recipe_detail(request, recipe_id): r=get_object_or_404(Recipe, pk=recipe_id) return render(request,'recipe/recipe_detail.html', {'recipe': r}) © Juergen Schackmann 2012 46/69
  • 47. Class Based (Generic) Views class RecipeDetailView(DetailView): model=Recipe #template_name='recipe/recipe_detail.html' << default class RecipeListView(ListView): model=Recipe template_name='recipe/my_recipe_list.html' << default ▸ Customizing via ▸ __init__ Parameter (ohne neue Klasse) ▸ Class Atrribute ▸ Methoden überschreiben ▸ Methoden überschreiben komplex, derzeit schwache Doku ▸ Achtung: class based views haben in UrlConf spezielle Syntax © Juergen Schackmann 2012 47/69
  • 48. Forms ▸ Eigenes Forms Package ▸ Initialisierung aus Model ▸ Automatisches Rendern in HTML ▸ Einfaches umwandlen von Post Request zurück in Model ▸ ModelForms ▸ Dynamische Generierung aus Model ▸ Hilfreiche App: ChrispyForms github.com/maraujop/django-crispy-forms ▸ Docs: docs.djangoproject.com/en/1.4/topics/forms © Juergen Schackmann 2012 48/69
  • 49. Form Handling Beispiel def edit(request, recipe_id): recipe = get_object_or_404(Recipe, pk=recipe_id) if request.method == 'POST': form = RecipeForm(instance=recipe, data=request.POST) if form.is_valid(): form.save() return HttpResponseRedirect(recipe.get_absolute_url()) else: form = RecipeForm(instance=recipe) return render(request, 'recipes/form.html', {'form': form, 'add': False, 'object': recipe}) © Juergen Schackmann 2012 49/69
  • 50. Url Konfiguration Model urls.py/ Django Url Konfigu- HTTP View raiton Handler Templates ▸ Mapping Tuple: Regex ==> Views ▸ Tuple Name: “urlpatterns” ▸ Regex Arguments als args und kwargs für View ▸ Named Patterns mit Reverese URL Lookup ▸ App Urls pluggable in Project Urls via Include © Juergen Schackmann 2012 50/69
  • 51. Typische App Url Konfiguration urlpatterns = patterns('recipes.views', url(r'^erstellen/$', 'add', name='recipes_recipe_add'), url(r'^bearbeiten/(?P<recipe_id>d+)/$', 'edit', name='recipes_recipe_edit'), url(r'^rezept/(?P<pk>[-w]+)/$', RecipeDetailView.as_view(), name='recipes_recipe_detail'), url(r'^$', RecipeListView.as_view(), name='recipes_recipe_index'), ) ▸ patterns(prefix,*list) ▸ Prefix: optional, gemeinsames Package für alle views ▸ url(regex,view, kwargs,name) ▸ view: view name als string oder callable ▸ kwargs (optional): zusätzliche default Parameter ▸ name(optional): beliebiger, aber eindeutiger name ▸ Weitere Syntaxvarianten möglich; siehe docs: docs.djangoproject.com/en/1.4/topics/http/urls/ © Juergen Schackmann 2012 51/69
  • 52. Typische Project Url Konfiguration admin.autodiscover() # ueblich wenn admin verwendet wird urlpatterns = patterns('', url(r'^$', 'recipes.views.home', name='home'), url(r'^recipes/', include('recipes.urls')), url(r'^admin/', include(admin.site.urls)), ) ▸ Vial Include werden Url Konfigurationen ineinander geschachtelt ▸ Vorallem App Urls ==> Project Urls ▸ Achtung: Url von Apps nicht fix, sondern abhängig von Project ==> reverse lookup © Juergen Schackmann 2012 52/69
  • 53. Reverse URL Lookup # in templates mit template tag {% url recipes_recipe_add %} # im python code reverse('recipes_recipe_detail', kwargs={'pk':id}) # via get_absolute_url und permalink decorator recipe.get_absolute_url() © Juergen Schackmann 2012 53/69
  • 54. Django Http Request Lifecycle Request View Url Config Model Middleware Middleware Django HTTP View Handler Response Exception Templates Middleware Middleware © Juergen Schackmann 2012 54/69
  • 55. Admin
  • 56. Django.contrib.admin ▸ Meistgenutzte Applikation ▸ Größter Django Selling Point ▸ Hierarchische Struktur ▸ Liste aller Apps ▸ Liste aller Models je App ▸ List und Detail View je Model ▸ Dynamische Generierung der Seiten auf Basis der Models ▸ Sehr umfangreiches Customizing möglich ▸ Unterschiedliche Admin Sites mit unterschiedlichen Ausprägungen möglich © Juergen Schackmann 2012 56/69
  • 57. Admin Beispiel class RecipeAdmin(admin.ModelAdmin): fields = ['title','preparation', 'date_created'] def get_query_set(self,request): return Recipe.objects.filter(active=True) admin.site.register(Category) admin.site.register(Recipe, RecipeAdmin) © Juergen Schackmann 2012 57/69
  • 58. Screenshots ▸ xxx © Juergen Schackmann 2012 58/69
  • 60. Settings.py ▸ Zentrale Konfiguration Django Project ▸ Python File ▸ 100+ Django Settings (mit sinnvollen defaults) ▸ Datenbank ▸ Apps ▸ Template Verzeichnisse ▸ Statische Verzeichnisse ▸ Middleware ▸ Locale, Timezone, … ▸ Kann auch for eigene App settings genutzt werden ▸ Docs: docs.djangoproject.com/en/1.4/ref/settings/ © Juergen Schackmann 2012 60/69
  • 61. Wichtige Settings Einstellungen ▸ DEBUG ▸ Datenbank ▸ Installed Apps ▸ Middleware ▸ Context_Processors ▸ Statische Verzeichnisse ▸ Template Verzeichnisse ▸ Timezone ▸ Locale © Juergen Schackmann 2012 61/69
  • 62. Typische Django App Liste (settings.py) INSTALLED_APPS = ( 'django.contrib.auth', << User Management, Authentifizierung, Autorisierung 'django.contrib.contenttypes', << Dependency für folgende 'django.contrib.sessions', << Session Management 'django.contrib.sites', << Betreiben mehrere Sites aus einem Projekt 'django.contrib.messages', << Messages im Browser 'django.contrib.staticfiles', << Statische files für Entwicklung und Deployment 'django.contrib.admin', << Admin für alle apps (sehr nützlich) 'south', << Datenschema Migration 'debug_toolbar' << Debug Toolbar im Browser (für Entwicklung) 'nuts1', << Custom App 'nuts2', << Custom App ) © Juergen Schackmann 2012 62/69
  • 63. Typische Settings Komponenten ▸ Bestimmung Project Root für generische Verweise auf Verzeichnisse PROJECT_ROOT = dir(abspath(__file__)) # Kann ff für Verzeichnisdefinition verwendet werden TEMPLATE_DIRS=(join(PROJECT_ROOT,'templates')) ▸ Definition von settings in Abhängigkeit von Debug setting if DEBUG: …. © Juergen Schackmann 2012 63/69
  • 64. Settings in komplexen Umgebungen ▸ Verteilung settings auf verschiedenen files ▸ Unterschiedliche Settings Files für unterschiedliche Umgebungen ▸ Import files in “master” settings file in Abhängigkeit von bestimmten Bedingungen import common_settings if environ('DJANGO_ENVIRONMENT')=='DEV': import dev_settings else: import prod_settings try: import local_settings except: pass © Juergen Schackmann 2012 64/69
  • 65. Zugriff auf Settings und App Settings ▸ Zugriff auf settings via django.conf.settings object ▸ Django Default Settings ▸ Project Settings ▸ Lazy Loading ▸ In settings.py sind nicht nur Django Core Settings erlaubt ▸ Jede App kann eigene settings definieren und nutzen from django.conf import settings NUTS_MY_SETTING =settings.get('NUTS_MY_SETTING','My_Default') © Juergen Schackmann 2012 65/69
  • 67. Pro Django ▸ Sehr flache Lernkurve ▸ Genügend Flexibilität bei komplexen Anforderungen ▸ Modulares Gesamtkonzept ▸ Sehr großes App Ökosystem ▸ Große Community und nachhaltige Entwicklung © Juergen Schackmann 2012 67/69
  • 68. “Batteries Included” ▸ Admin ▸ Session Handling ▸ User Management, Authentifizeirung, Authorisierung, Permissions ▸ Comments ▸ Tags ▸ Static Files ▸ Content Types ▸ Internationalisierung, Lokalisierung ▸ Caching © Juergen Schackmann 2012 68/69
  • 69. Room for Improvement ▸ Convention sehr liberal ▸ Pluggable != Pluggable ▸ Viele Apps für das selbe Problem ▸ Qualität der Apps sehr unterschiedlich ▸ Fehlende Contrib Apps: ▸ Workflow ▸ Object Permissions ▸ Schema Migration ▸ Python 3 support für apps © Juergen Schackmann 2012 69/69