Django - A Whirlwind Tour 2016

Django - A Whirlwind Tour 2016

Slides for my talk given at DevSpace Conf 2016 -- Django is a leading web development framework written in Python, and has long been billed as "the web framework for perfectionists with deadlines".

This talk will quickly walk you through a typical django project, illustrating some of django's "batteries included" features and some common conventions used in many apps.

D57aec10399cbb252bd890c2bb3fe1c9?s=128

Brad Montgomery

October 14, 2016
Tweet

Transcript

  1. Django: A Whirlwind Tour Brad Montgomery @bkmontgomery

  2. Who is this guy? • Working with Python + Django

    since 2009 • Tech Lead at Tennessee Data Commons (501c3) • MEMpy Organizer • “full-stack” web developer.
  3. Django: Features • MVC-inspired (MVT) • Security. • A large

    community / Lots of open source • Worlds Best Documentation • The web framework for perfectionists with deadlines.
  4. Django: Neat Facts • Since 2005 • 1200+ Contributors •

    django.tar.gz ~ 8Mb • 94% python • 261,776 lines of code (w/ comments)
  5. Batteries Included • ORM • Django Template Language • Testing

    Framework (unittest) • Contrib apps: • Commonly needed things bundled with Django. • Admin, Syndication, Flash messages, GIS
  6. djangoproject.com Latest Release: 1.10 LTS Release: 1.8

  7. So, who’s using Django?

  8. The Washington Post, National Geographic, The Onion, Eventbrite, Pintrest, Disqus,

    Mozilla, edX
  9. Community • The Python Community • Meetups / Conferences (DjangoCon)

    • 3rd-party, open source apps • django-registration (signup, account reset) • django-taggit (Tagging content) • django-storages (File storage on S3) • django-crispy-forms (Form layout tools) • Django REST Framework (restful apis)
  10. More Open Source • Django CMS • Wagtail • Mezzanine

  11. djangopackages.com 3276 packages

  12. So, what does a Django project look like?

  13. Projects & Apps • Projects are a collection of Django

    apps. • MDN: https://developer.mozilla.org/ • API that powers a mobile app (app.tndata.org) • Settings, DB, Apps, Filesystem info. • Command-line tool: manage.py
  14. Projects & Apps $ django-admin.py startproject foo Super-clever project name

  15. Projects & Apps foo/ ├── manage.py └── foo/ ├── __init__.py

    ├── settings.py ├── urls.py └── wsgi.py Project directory
  16. Projects & Apps foo/ ├── manage.py └── foo/ ├── __init__.py

    ├── settings.py ├── urls.py └── wsgi.py Project- specific CLI
  17. Projects & Apps foo/ ├── manage.py └── foo/ ├── __init__.py

    ├── settings.py ├── urls.py └── wsgi.py Project settings, etc
  18. Migrate $ python manage.py migrate

  19. Projects & Apps $ python manage.py runserver Dev server running

    at: 127.0.0.1:8000
  20. Projects & Apps

  21. Projects & Apps $ python manage.py startapp blog Another creative

    app name.
  22. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py App directory
  23. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py (special python file)
  24. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py Admin Config
  25. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py App Config
  26. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py Database Migrations
  27. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py Data Models
  28. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py (Unit) Tests
  29. Projects & Apps foo/ ├── blog ├── __init__.py ├── admin.py

    ├── apps.py ├── migrations/ ├── models.py ├── tests.py └── views.py Http Request handlers. (Controllers)
  30. Models from django.db import models from django.contrib.auth.models import User class

    Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=128) slug = models.SlugField(max_length=128, unique=True) content = models.TextField() published_on = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['published_on', ] verbose_name = "Post" verbose_name_plural = "Posts" foo/blog/models.py
  31. Models from django.db import models from django.contrib.auth.models import User class

    Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=128) slug = models.SlugField(max_length=128, unique=True) content = models.TextField() published_on = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['published_on', ] verbose_name = "Post" verbose_name_plural = "Posts" foo/blog/models.py
  32. Models from django.db import models from django.contrib.auth.models import User class

    Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=128) slug = models.SlugField(max_length=128, unique=True) content = models.TextField() published_on = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['published_on', ] verbose_name = "Post" verbose_name_plural = "Posts" foo/blog/models.py
  33. Models from django.db import models from django.contrib.auth.models import User class

    Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=128) slug = models.SlugField(max_length=128, unique=True) content = models.TextField() published_on = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['published_on', ] verbose_name = "Post" verbose_name_plural = "Posts" foo/blog/models.py
  34. Models from django.db import models from django.contrib.auth.models import User class

    Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=128) slug = models.SlugField(max_length=128, unique=True) content = models.TextField() published_on = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['published_on', ] verbose_name = "Post" verbose_name_plural = "Posts" foo/blog/models.py
  35. Views from django.shortcuts import render from .models import Post def

    list_posts(request): context = { 'posts': Post.objects.all(), } template = "blog/list.html" return render(request, template, context) foo/blog/views.py
  36. Views from django.shortcuts import render from .models import Post def

    list_posts(request): context = { 'posts': Post.objects.all(), } template = "blog/list.html" return render(request, template, context) foo/blog/views.py
  37. Views from django.shortcuts import render from .models import Post def

    list_posts(request): context = { 'posts': Post.objects.all(), } template = "blog/list.html" return render(request, template, context) foo/blog/views.py
  38. Views from django.shortcuts import render from .models import Post def

    list_posts(request): context = { 'posts': Post.objects.all(), } template = "blog/list.html" return render(request, template, context) foo/blog/views.py
  39. A base template <!DOCTYPE html> <html> <head> <title> {% block

    title %}{% endblock %} </title> </head> <body> {% block content %}{% endblock %} </body> </html> blog/templates/blog/base.html
  40. A base template <!DOCTYPE html> <html> <head> <title> {% block

    title %}{% endblock %} </title> </head> <body> {% block content %}{% endblock %} </body> </html> blog/templates/blog/base.html
  41. A list template {% extends "blog/base.html" %} {% block title

    %} Posts {% endblock %} {% block content %} <h1>Posts</h1> <ul> {% for post in posts %} <li> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> posted {{ post.published_on|timesince }} ago. </li> {% endfor %} </ul> {% endblock %} blog/templates/blog/list.html
  42. A list template {% extends "blog/base.html" %} {% block title

    %} Posts {% endblock %} {% block content %} <h1>Posts</h1> <ul> {% for post in posts %} <li> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> posted {{ post.published_on|timesince }} ago. </li> {% endfor %} </ul> {% endblock %} blog/templates/blog/list.html
  43. A list template {% extends "blog/base.html" %} {% block title

    %} Posts {% endblock %} {% block content %} <h1>Posts</h1> <ul> {% for post in posts %} <li> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> posted {{ post.published_on|timesince }} ago. </li> {% endfor %} </ul> {% endblock %} blog/templates/blog/list.html
  44. A list template {% extends "blog/base.html" %} {% block title

    %} Posts {% endblock %} {% block content %} <h1>Posts</h1> <ul> {% for post in posts %} <li> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> posted {{ post.published_on|timesince }} ago. </li> {% endfor %} </ul> {% endblock %} blog/templates/blog/list.html
  45. A list template {% extends "blog/base.html" %} {% block title

    %} Posts {% endblock %} {% block content %} <h1>Posts</h1> <ul> {% for post in posts %} <li> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> posted {{ post.published_on|timesince }} ago. </li> {% endfor %} </ul> {% endblock %} blog/templates/blog/list.html
  46. URL Conf’s • Tie it all together! • Route HTTP

    requests to views (functions) • May also capture values using Regex
  47. Root URLConf from django.conf.urls import include, url from django.contrib import

    admin urlpatterns = [ url(r’^blog/', include(‘blog.urls’)), url(r'^admin/', include(admin.site.urls)), ] foo/foo/urls.py Part of your project config.
  48. Root URLConf from django.conf.urls import include, url from django.contrib import

    admin urlpatterns = [ url(r’^blog/', include(‘blog.urls’)), url(r'^admin/', include(admin.site.urls)), ] foo/foo/urls.py Part of your project config.
  49. Root URLConf from django.conf.urls import include, url from django.contrib import

    admin urlpatterns = [ url(r’^blog/', include(‘blog.urls’)), url(r'^admin/', include(admin.site.urls)), ] foo/foo/urls.py Part of your project config.
  50. Root URLConf from django.conf.urls import include, url from django.contrib import

    admin urlpatterns = [ url(r’^blog/', include(‘blog.urls’)), url(r'^admin/', include(admin.site.urls)), ] foo/foo/urls.py Part of your project config. example.com/blog/hello-world
  51. Root URLConf from django.conf.urls import include, url from django.contrib import

    admin urlpatterns = [ url(r’^blog/', include(‘blog.urls’)), url(r'^admin/', include(admin.site.urls)), ] foo/foo/urls.py Part of your project config.
  52. Our app’s URLs from django.conf.urls import url from . import

    views urlpatterns = [ url(r'^$', views.list_posts, name='list_posts'), url(r’^(?P<post_slug>.+)/$', views.display_post, name='display_post'), ] foo/blog/urls.py
  53. Our app’s URLs from django.conf.urls import url from . import

    views urlpatterns = [ url(r'^$', views.list_posts, name='list_posts'), url(r’^(?P<post_slug>.+)/$', views.display_post, name='display_post'), ] foo/blog/urls.py
  54. Our app’s URLs from django.conf.urls import url from . import

    views urlpatterns = [ url(r'^$', views.list_posts, name='list_posts'), url(r’^(?P<post_slug>.+)/$', views.display_post, name='display_post'), ] foo/blog/urls.py example.com/blog/
  55. Our app’s URLs from django.conf.urls import url from . import

    views urlpatterns = [ url(r'^$', views.list_posts, name='list_posts'), url(r’^(?P<post_slug>.+)/$', views.display_post, name='display_post'), ] foo/blog/urls.py
  56. Our app’s URLs from django.conf.urls import url from . import

    views urlpatterns = [ url(r'^$', views.list_posts, name='list_posts'), url(r’^(?P<post_slug>.+)/$', views.display_post, name='display_post'), ] foo/blog/urls.py example.com/blog/hello-world
  57. “Installing” our app. INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions',

    'django.contrib.messages', ‘django.contrib.staticfiles', 'blog', ] foo/foo/settings.py
  58. Migrate $ python manage.py \ make migrations blog

  59. Migrate $ python manage.py migrate

  60. Let’s follow an HTTP request through a detail view.

  61. An HTTP Request

  62. An HTTP Request from django.conf.urls import include, url from django.contrib

    import admin urlpatterns = [ url(r’^blog/', include(‘blog.urls’)), url(r'^admin/', include(admin.site.urls)), ] foo/foo/urls.py — The Root URLConf blog/sample-title/
  63. An HTTP Request urlpatterns = [ url(r'^$', views.list_posts, name='list_posts'), url(r’^(?P<post_slug>.+)/$',

    views.display_post, name='display_post'), ] foo/blog/urls.py — App URLConf blog/sample-title/
  64. An HTTP Request def display_post(request, post_slug): context = { 'post':

    Post.objects.get(slug=post_slug) } template = "blog/post.html" return render(request, template, context) foo/blog/views.py sample-title
  65. An HTTP Request {% extends "blog/base.html" %} {% block title

    %} {{ post.title }} {% endblock %} {% block content %} <h1>{{ post.title }}</h1> {{ post.content|urlize|linebreaks }} <p>Published on: {{ post.published_on|date:"M d, Y" }}</p> {% endblock %} foo/blog/templates/blog/post.html Sample Title
  66. An HTTP Request {% extends "blog/base.html" %} {% block title

    %} {{ post.title }} {% endblock %} {% block content %} <h1>{{ post.title }}</h1> {{ post.content|urlize|linebreaks }} <p>Published on: {{ post.published_on|date:"M d, Y" }}</p> {% endblock %} foo/blog/templates/blog/post.html Lorem Ipsum...
  67. An HTTP Request {% extends "blog/base.html" %} {% block title

    %} {{ post.title }} {% endblock %} {% block content %} <h1>{{ post.title }}</h1> {{ post.content|urlize|linebreaks }} <p>Published on: {{ post.published_on|date:"M d, Y" }}</p> {% endblock %} foo/blog/templates/blog/post.html Oct 14, 2016
  68. An HTTP Request

  69. Cool but how do I create a post?

  70. Cheat: Django Admin

  71. The Django Admin from django.contrib import admin from .models import

    Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ( 'title', 'author', ‘published_on' ) prepopulated_fields = {"slug": ("title",)} foo/blog/admin.py
  72. The Django Admin from django.contrib import admin from .models import

    Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ( 'title', 'author', ‘published_on' ) prepopulated_fields = {"slug": ("title",)} foo/blog/admin.py
  73. The Django Admin from django.contrib import admin from .models import

    Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ( 'title', 'author', ‘published_on' ) prepopulated_fields = {"slug": ("title",)} foo/blog/admin.py
  74. The Django Admin from django.contrib import admin from .models import

    Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ( 'title', 'author', ‘published_on' ) prepopulated_fields = {"slug": ("title",)} foo/blog/admin.py
  75. Model Forms… from django.forms.models import ModelForm from .models import Post

    class PostForm(ModelForm): class Meta: model = Post fields = ('title', 'content' )
  76. Model Forms… @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ( 'title', 'author',

    ‘published_on' ) form = PostForm
  77. Other Tools • Forms: Generate form UI, & sanitize/ validate

    user input. • The ORM: Complex Queries, Custom Managers (table-level queries), Aggregates, dropping to raw SQL. • Middleware: Doing stuff on every request • Security, Caching, Logging, custom manage.py commands…
  78. But what about production?

  79. A Typical Stack Linux

  80. A Typical Stack Linux PostgreSQL

  81. A Typical Stack Linux PostgreSQL Gunicorn + Django

  82. A Typical Stack Linux PostgreSQL Gunicorn + Django nginx

  83. A Typical Stack PostgreSQL Gunicorn + Django Gunicorn + Django

    nginx
  84. A Typical Stack PostgreSQL Gunicorn + Django Gunicorn + Django

    nginx PostgreSQL writes reads repl.
  85. A Typical Stack PostgreSQL Gunicorn + Django Gunicorn + Django

    nginx PostgreSQL writes reads repl. Redis Memcached RabbitMQ Varnish
  86. None
  87. Heroku. Easy. • Deploy & Scale in the Cloud •

    Sign up at heroku.com • Get the Heroku CLI • Deploying Python and Django Apps on Heroku
  88. Deploy to Heroku $ git push heroku master After a

    bit of setup…
  89. Learn More? • Official Django Docs • Hello Web App

    by Tracy Osborne • Design and build your own custom web app using Python and Django. Tailored for non- programmers, written by a designer. • Two Scoops of Django by Daniel & Audrey Roy Greenfeld • github.com/bradmontgomery/whirlwind_tour
  90. Live Demo!

  91. Thanks! Questions?

  92. None