unchain your web development with django
TRANSCRIPT
Unchain Your Web Development with Django
The web framework for perfectionists with deadlines.
Who am I?
● Started using Python 1.5.2 in 1998
● Started using Django 0.96 in 2008
● Contributing to open source projects since ~2000
● @mrbeersnob
● github.com/tarkatronic
What is Django?
No, really, what is it?
The web framework for professionals with deadlines
● Originally built for the Lawrence Journal-World newspaper in 2003
● A bundled collection of tools to build powerful web applications quickly
● Focused on automation and DRY
Who actually uses this thing?
● Disqus
● Washington Post
● National Geographic
● Many, many more…
● https://www.djangosites.org/
Why should I use it?
● ORM
● Caching
● Internationalization
● Class-based views!
● Templating
● Automatically generated admin interface
● Database migrations
● Built-in management commands
Django doesn’t provide ____. Do I have to build it?
● Social authentication? django-allauth
● REST API? django-rest-framework
● Two factor authentication? django-two-factor-auth
● CMS? wagtail, django-cms, etc
● https://www.djangopackages.com/
● https://djangosnippets.org/
Let’s get started!
Setting things up
● pip install Django
● django-admin.py startproject cocktails
● …
● Profit!
Okay, maybe a little more than that../manage.py runserver…Starting development server at http://127.0.0.1:8000/
Creating an application
django-admin.py startapp recipes
recipes/migrations/
__init__.py__init__.pyadmin.pymodels.pytests.pyviews.py
settings.py:INSTALLED_APPS = (
…'cocktails.recipes'
)
First step: Modelsfrom django.db import models
class Ingredient(models.Model): OUNCE = 'ounce' TEASPOON = 'tsp' TABLESPOON = 'tbsp' DASH = 'dash'
MEASUREMENTS = ( (OUNCE, 'Ounce(s)'), (TEASPOON, 'Teaspoon(s)'), (TABLESPOON, 'Tablespoon(s)'), (DASH, 'Dash(es)'), ) name = models.CharField(max_length=255) measurement = models.CharField(max_length=5, choices=MEASUREMENTS, null=True, blank=True)
def __str__(self): return self.name
A couple more...class Drink(models.Model): name = models.CharField(max_length=255) components = models.ManyToManyField('Ingredient', through='Component', related_name='drinks')
def __str__(self): return self.name
class Component(models.Model): drink = models.ForeignKey('recipes.Drink', related_name='+') ingredient = models.ForeignKey('recipes.Ingredient', related_name='+') amount = models.FloatField()
def __str__(self): return '%s %s %s (%s)' % (self.ingredient.name, self.amount, self.ingredient.get_measurement_display() or '', self.drink.name)
One more piececlass Step(models.Model): drink = models.ForeignKey('Drink', related_name='steps') text = models.TextField()
class Meta: order_with_respect_to = 'drink'
def __str__(self): return '%s step #%s' % (self.drink.name, self._order + 1)
Time to set up the database...
CREATE DATABASE;CREATE TABLE …;
...right?
Nope! Migrations to the rescue../manage.py makemigrationsMigrations for 'recipes': 0001_initial.py: - Create model Component - Create model Drink - Create model Ingredient - Create model Step - Add field components to drink - Add field drink to component - Add field ingredient to component - Set order_with_respect_to on step to drink
./manage.py migrateOperations to perform: Synchronize unmigrated apps: staticfiles, messages Apply all migrations: admin, contenttypes, recipes, auth, sessions … lots more words …
Done!
About that admin interface...
admin.py:from django.contrib import adminfrom .models import Component, Drink, Ingredient, Step
class ComponentInline(admin.TabularInline): model = Component
class StepInline(admin.StackedInline): model = Step
class DrinkAdmin(admin.ModelAdmin): inlines = [ComponentInline, StepInline]
admin.site.register(Component)admin.site.register(Drink)admin.site.register(Ingredient)admin.site.register(Step)
Creating an admin user
Another built-in management command!
./manage.py createsuperuserUsername (leave blank to use 'jwilhelm'):Email address: [email protected]:Password (again):Superuser created successfully.
Log in, and like magic, we get...
Adding some records
Our inlines at work
Making things visible: views
views.py:from django.core.urlresolvers import reverse_lazyfrom django.views.generic import DetailView, ListView
from .models import Component, Drink
class DrinkListView(ListView): model = Drink
class DrinkDetailView(DetailView): model = Drink
def get_context_data(self, **kwargs): context = super(DrinkDetailView, self).get_context_data(**kwargs) context.update({'components': Component.objects.filter(drink=self.get_object())}) return context
Pulling it together with a couple templates
base.html:
<html> <head> <title>Cocktail Database</title> </head> <body> {% block content %}{% endblock %} </body></html>
List all the things!
recipes/drink_list.html:
{% extends "base.html" %}
{% block content %} {% for drink in object_list %} {% if forloop.first %} <ul> {% endif %} <li><a href="{% url 'drink_detail' drink.id %}">{{ drink.name }}</a></li> {% if forloop.last %} </ul> {% endif %} {% empty %} No drinks yet in the database. {% endfor %}{% endblock %}
It's all in the details
recipes/drink_detail.html:
{% extends "base.html" %}
{% block content %} <h1>{{ drink.name }}</h1> <dl> <dt>Ingredients</dt> <dd> <ul> {% for component in components %} <li>{{ component.amount }}{% if component.ingredient.measurement %} {{ component.ingredient.measurement }}{% endif %} {{ component.ingredient.name }}</li> {% endfor %} </ul> </dd>...
Details, continued... <td>Steps</td> <dd> <ol> {% for step in drink.steps.all %} <li>{{ step.text }}</li> {% endfor %} </ol> </dd> </dl>{% endblock %}
Just one more piece: urls
urls.py:
from cocktails.recipes.views import DrinkDetailView, DrinkListView
urlpatterns = [ ... url(r'^drinks/$', DrinkListView.as_view(), name='drink_list'), url(r'^drinks/(?P<pk>[0-9]+)/$', DrinkDetailView.as_view(), name='drink_detail'),]
The (ugly, ugly) fruits of our labor
The (slightly less ugly) details
The full code, plus a bit more
django-cocktails repository: https://github.com/tarkatronic/django-cocktails
What if I need help?
“I came for the auto generated admin, but I stayed for the community.”-Ola Sitarska
● StackOverflow - http://stackoverflow.com/questions/tagged/django
● django-users mailing list - https://groups.google.com/forum/#!forum/django-users
● IRC: #django on Freenode (I'm often on as TheJoey)
Now, go learn more!
Django Project website: http://www.djangoproject.com/
Django Girls tutorial: http://tutorial.djangogirls.org/
Getting Started with Django: http://gettingstartedwithdjango.com/
Two Scoops of Django: http://twoscoopspress.org/
Cheers!