Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Web Development with Python and Django (2015)

E4c5e3c69566ff80db62a4ab521b6e5a?s=47 Mike Pirnat
January 06, 2015

Web Development with Python and Django (2015)

Slide deck from the CodeMash 2015 edition of the "Web Development with Python and Django" tutorial by Mike Pirnat and David Stanek, featuring the "Dungeons & Djangos" sample application.

E4c5e3c69566ff80db62a4ab521b6e5a?s=128

Mike Pirnat

January 06, 2015
Tweet

Transcript

  1. Web Development with Python and Django Mike Pirnat • David

    Stanek • CodeMash 2015
  2. About Us Mike Pirnat American Greetings http://mike.pirnat.com @mpirnat David Stanek

    Rackspace http://traceback.org @dstanek
  3. Today •Iteratively build a full-featured site •Describe a feature we

    need •Implement a feature together •Review our example solution • Keep yours? git show tag • Follow directly? git reset --hard tag
  4. Useful Links •http://docs.python.org •https://docs.djangoproject.com •https://github.com/mpirnat/django-tutorial-v2

  5. Let’s Have a Show of Hands...

  6. Everything* You Need to Know About Python in One Slide

    *(more or less)
  7. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  8. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  9. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  10. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  11. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  12. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  13. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  14. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  15. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  16. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  17. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  18. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  19. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  20. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  21. from module.submodule import SomeClass class MyClass(SomeClass): "This explains what the

    class is about." def method(self, x, y=1): "This explains what the method does." dictionary = {'key1': 'val1', 'key2': 'val2'} if y == 1: return ["Hello", dictionary['key1']] else: return ["World", dictionary.get(x, 'val3')] instance = MyClass() for word in instance.method(42): print(word)
  22. Django

  23. Django?

  24. Django?

  25. Django! •A high-level Python web framework •Encourages rapid development and

    clean, pragmatic design •“For perfectionists with deadlines” •Focus on automation and DRY •Widely supported, many deployment options
  26. Perhaps You’ve Heard Of... •Disqus •Instagram •Mozilla •OpenStack •Pinterest •PolitiFact.com

    •Rdio
  27. Django •ORM •Automatic admin interface •Regex-based URL design •Templating system

    •Cache infrastructure •Internationalization •Command-line job framework
  28. The Django Stack

  29. Django

  30. Django Request

  31. Django Request Response

  32. Django Request Response

  33. Django Framework Request Response

  34. Django Framework Middleware Request Response

  35. Django Framework Middleware URLs Request Response

  36. Django Framework Middleware URLs Views Request Response

  37. Django Framework Middleware URLs Views Models Request Response

  38. Django Framework Middleware URLs Views Models DB Request Response

  39. Django Framework Middleware URLs Views Models Templates DB Request Response

  40. Framework Middleware URLs Views Models Templates DB Tags & Filters

    Request Response
  41. Setup

  42. Download and Install •Python 3.4 – https://python.org/downloads (or get it

    from your Linux distro’s package manager) •Git – http://git-scm.com
  43. Got Ubuntu? •Ubuntu’s Python 3.4 is currently broken •Prevents normal

    setup of virtual environments •We have a cloud server already set up that you can use –104.130.195.216 •Or make a new friend
  44. Got Windows? •Be sure to update the PATH so that

    Windows can find your scripts: C:\Python34\;C:\Python34\Scripts\;C:\Python34\Tools \Scripts
  45. Installing Packages •pip install package •Installed packages go into a

    site-packages directory in your Python lib •That’s the “system Python” by default •But different programs may need different versions of packages... •So we have virtual environments!
  46. Virtual Environments •Creates an isolated Python environment with its own

    site-packages •Install whatever you want without fouling anything else up •Now part of the standard library
  47. Create & Activate the Virtual Environment # Mac/Linux/etc... $ pyvenv

    django-tutorial-v2 $ cd django-tutorial-v2 $ source bin/activate # Windows > pyvenv.py django-tutorial-v2 > cd django-tutorial-v2 > Scripts\activate.bat
  48. Get the Example Code # Normally... $ git init src

    # Today... $ git clone https://github.com/mpirnat/django-tutorial- v2.git ./src
  49. Defining Requirements •requirements.txt •A basic example: MyApp Framework==0.9.4 Library>=0.2 http://someserver.org/packages/MyPackage-3.0.tar.gz

  50. Installing Requirements # Still in the 'src' directory from before...

    # Mac/Linux/etc... $ cd src $ pip install -r requirements.txt # Windows > cd src > pip.exe install -r requirements.txt
  51. Check Prerequisites # In that same 'src' directory... # Mac/Linux/etc...

    $ python prerequisites.py # Windows > python.exe prerequisites.py
  52. Rewind to the Start of Exercises # In that same

    'src' directory... $ git reset --hard exercise01.1
  53. The Project...

  54. “Dungeons & Djangos” •Web-based fantasy role playing game •Inspired by

    D&D (5E is great, btw) •We’ll build the core of the app: • character creation • user registration, login/logout • admin interface • a fancy landing page
  55. 1. Start the Project

  56. Starting a Project •Mac/Linux: $ django-admin.py startproject projectname ./ $

    python manage.py runserver •Windows: > python Scripts\django-admin.py startproject projectname > python manage.py runserver
  57. git reset --hard exercise01.1 | git show solution01.1 Exercise 1.1

    •Start a new project “mysite” •Run the server •Open your browser to localhost:8000
  58. New Project Contents src/ mysite/ __init__.py settings.py urls.py wsgi.py manage.py

  59. Start an App •Django believes strongly in separating chunks of

    a site into apps that can be reused •Ecosystem of reusable apps available •Create an app; from the src directory: $ python manage.py startapp myapp •Add it to INSTALLED_APPS in settings.py
  60. git reset --hard exercise01.2 | git show solution01.2 Exercise 1.2

    •Start a new app named “characters”
  61. New App Contents src/ mysite/ characters/ __init__.py admin.py models.py tests.py

    <-- you should write them! views.py migrations/
  62. git reset --hard exercise01.3 | git show solution01.3 Exercise 1.3

    •Add the characters app to the list of INSTALLED_APPS in settings.py
  63. 2. Create a Character Model

  64. Models •Model classes are the nouns of the system •Used

    to create database tables •Integrated with the ORM to interact with the database •Need to create & run migrations when adding or changing model classes
  65. git reset --hard exercise02.1 | git show solution02.1 Exercise 2.1

    •Create a Character model; it should have: • name – text, up to 200 characters • background – text, open-ended • level, experience_points, max_hit_points, current_hit_points – integers • strength, dexterity, constitution, intelligence, wisdom, charisma – integers • created, modified – datetimes, automatically populated • a __str__ method that returns the character’s name
  66. Migrations •Propagates model changes into the database •Keeps a record

    of changes made to the models •Can migrate forward and backward •Formerly provided by third-party tools •New in Django 1.7, required by Django 1.9
  67. Making & Running Migrations •Creating a migration for an app:

    $ python manage.py makemigrations <app> •See the SQL that will be executed: $ python manage.py sqlmigrate <app> <number> •Run migrations: $ python manage.py migrate
  68. git reset --hard exercise02.2 | git show solution02.2 Exercise 2.2

    •Create a migration for the initial version of the Character model •Run the migration
  69. Trying Out the Model •Start a Python shell with all

    the Django stuff all ready to go: $ python manage.py shell •Now we can test out our model
  70. Try the Admin Interface •Django comes with a built-in admin

    interface to explore and manipulate models •Runs on /admin/ by default •Need to create an admin superuser: $ python manage.py createsuperuser •Need to register models in the app’s admin.py
  71. git reset --hard exercise02.3 | git show solution02.3 Exercise 2.3

    •Create a superuser for using the admin interface •Register the Character model for use with the admin interface •Open your browser to localhost:8000/ admin
  72. 3. Add Some Defaults to the Character Model

  73. Worthwhile Defaults •Level •Experience points •Hit points •Stats – simulate

    dice rolling!
  74. Anatomy of a Dice Roll

  75. Anatomy of a Dice Roll 2d8+ 1

  76. Anatomy of a Dice Roll 2d8+ 1 number of dice

  77. Anatomy of a Dice Roll 2d8+ 1 type of die

    number of dice
  78. Anatomy of a Dice Roll 2d8+ 1 type of die

    number of dice modifier
  79. git reset --hard exercise03.1 | git show solution03.1 Exercise 3.1

    •Add defaults to the Character model: • level – default to 1 • experience_points – default to 0 • max_hit_points, current_hit_points – default to 10 • stats (strength, dexterity, etc.) – use a function that uses Python’s random.randint to model a 3d6 dice roll
  80. git reset --hard exercise03.2 | git show solution03.2 Exercise 3.2

    •Extract dice rolling from stat generation so that we can model any XdY + Z dice roll •Can do it in a one-line function •Don’t panic — this is the weirdest the code gets today!
  81. 4. Add Alignment to the Character Model

  82. Choices •When a field can have only a finite set

    of values that won’t change often, use choices •Can define both database native values and their human-friendly equivalents that will be displayed in the app
  83. git reset --hard exercise04.1 | git show solution04.1 Exercise 4.1

    •Add alignment to the Character model; it should have a fixed set of choices: • Lawful Good • Lawful Neutral • Lawful Evil • Neutral Good • Neutral • Neutral Evil •It should default to Neutral • Chaotic Good • Chaotic Neutral • Chaotic Evil
  84. git reset --hard exercise04.2 | git show solution04.2 Exercise 4.2

    •Create the migration to add alignment to the Character model •Run the migration
  85. 5. Add Race and Class

  86. Foreign Keys •Use a separate model when the data is

    too rich for a simple set of choices •When a model (Character) can be related to only one of some other model (Race, Class), use a ForeignKey •When using the model, need an instance: hobbit = Race('hobbit').save() bilbo = Character(..., race=hobbit)
  87. Foreign Keys •Have to be careful when adding non-null fields

    to an existing model, doubly so when it’s a ForeignKey •Migration will ask for a default •If adding a new model and an FK relationship, no defaults yet! •Do it in several steps...
  88. git reset --hard exercise05.1 | git show solution05.1 Exercise 5.1

    •Create very basic models for Race and Class; they should each have: • name – text, up to 200 characters • description – text, open-ended • a __str__ method that returns the name
  89. git reset --hard exercise05.2 | git show solution05.2 Exercise 5.2

    •Create the migration to create the Race and Class models in the database •Run the migration
  90. git reset --hard exercise05.3 | git show solution05.3 Exercise 5.3

    •Add a ForeignKey relationship from the Race model to the Character model •Add a ForeignKey relationship from the Class model to the Character model •Be careful about names here; “class” is a Python builtin that we don’t want to shadow
  91. Data Migrations •Adding default values into a DB is best

    accomplished with data migrations •Allow you to reliably populate data at the right point in the evolution of the DB •To create one: $ python manage.py makemigrations --empty appname
  92. git reset --hard exercise05.4 | git show solution05.4 Exercise 5.4

    •Create a data migration that populates a default race (“Human”) and class (“Generic”) into the database •Run the migration
  93. git reset --hard exercise05.5 | git show solution05.5 Exercise 5.5

    •Create a migration to add the ForeignKey relationships for Character/Race and Character/Class •Run the migration •When prompted for a default for the FK, enter the id you want (in this case 1 to match the data migration)
  94. git reset --hard exercise05.6 | git show solution05.6 Exercise 5.6

    •Register the Race and Class models for use with the admin interface •What do you notice about the Class model in the admin interface?
  95. git reset --hard exercise05.7 | git show solution05.7 Exercise 5.7

    •Fix the pluralization of “class” in the admin interface by adding verbose_name_plural metadata to the Class model •Observe the change in the admin app •What do you notice about how the class appears when looking at a character?
  96. git reset --hard exercise05.8 | git show solution05.8 Exercise 5.8

    •Add a verbose_name of “class” to the Character/Class ForeignKey in the Character model •Observe the change in the admin interface
  97. git reset --hard exercise05.9 | git show solution05.9 Exercise 5.9

    •Create a migration to sync up the previous change •Run the migration
  98. 6. Inventory

  99. Many-to-Many Relations •When a model (Character) can be related to

    many of some other model (Item), use a ManyToManyField •When using the model, need a list of instances: arkenstone = Item(name='Arkenstone').save() sting = Item(name='Sting (shortsword)').save() bilbo.inventory = [arkenstone, sting]
  100. git reset --hard exercise06.1 | git show solution06.1 Exercise 6.1

    •Create an Item model; it should have: • name – text, up to 200 characters • description – text, open-ended • value – integer, default to 0 • weight – integer, default to 1 • a __str__ method that returns the name •Add a ManyToMany relation between Character and Item to the Character
  101. git reset --hard exercise06.2 | git show solution06.2 Exercise 6.2

    •Create a migration to add the Item model and the ManyToMany relation to the database •Run the migration
  102. git reset --hard exercise06.3 | git show solution06.3 Exercise 6.3

    •Register the Item model for use with the admin interface •Create an Item using the admin interface •Edit a Character in the admin interface; add an item to it •Create a Character without any items in the admin interface; what do you notice?
  103. git reset --hard exercise06.4 | git show solution06.4 Exercise 6.4

    •Change the ManyToMany to be nullable and blank
  104. git reset --hard exercise06.5 | git show solution06.5 Exercise 6.5

    •Create a migration to alter the relationship •Run the migration •Observe the change in the admin app
  105. 7. Basic Admin Customizations

  106. git reset --hard exercise07.1 | git show solution07.1 Exercise 7.1

    •Modify the admin wiring to group character fields in meaningful groups: • name, level, class, background • max hit points, current hit points • stats (strength, dexterity, constitution, intelligence, wisdom, charisma) • experience points, inventory
  107. git reset --hard exercise07.2 | git show exercise07.2 Exercise 7.2

    •Make the character’s creation and modification dates appear in the admin interface •Show the creation and modification dates in a separate fieldset
  108. git reset --hard exercise07.3 | git show solution07.3 Exercise 7.3

    •Add more fields to the character list in the admin interface: • name • level • race • class • creation & modification dates
  109. git reset --hard exercise07.4 | git show solution07.4 Exercise 7.4

    •Add filters for race, class, creation, and modification date to the admin interface
  110. git reset --hard exercise07.5 | git show solution07.5 Exercise 7.5

    •Change the model name of Race.name to “race” •Change the model name of Class.name to “class”
  111. git reset --hard exercise07.6 | git show solution07.6 Exercise 7.6

    •Create the migration for adding model names to Race.name and Class.name •Run the migration
  112. git reset --hard exercise07.7 | git show solution07.7 Exercise 7.7

    •Add search capability to the character list in the admin interface •Make characters searchable by name, background, race, and class
  113. 8. Add Basic Views

  114. URLs •Map URLs in requests to code that can be

    executed •Regular expressions! •Each app has its own urls.py
  115. Views •Code that handles requests •Other frameworks often call these

    “controllers” •Basically a function that: • gets a request passed to it • returns text or a response
  116. git reset --hard exercise08.1 | git show solution08.1 Exercise 8.1

    •Create a simple view in the characters app •It can just emit “hello world” for now •Create a URL mapping for /characters/ to this view
  117. git reset --hard exercise08.2 | git show solution08.2 Exercise 8.2

    •Create a stub view for viewing details of a single character •The URL should include the character_id •The view should say which character_id is being displayed •The view does NOT need to query the DB
  118. git reset --hard exercise08.3 | git show solution08.3 Exercise 8.3

    •Change the character index view to return a list of all characters •Change the character detail view to return the requested single character
  119. 9. Templates & Basic Improvements

  120. Django Template Language •Call a function or do logic: {%

    ... %} •Variable substitution: {{ bar }} •Filters: {{ foo|bar }}
  121. git reset --hard exercise09.1 | git show solution09.1 Exercise 9.1

    •Create a template to list characters •Change the character list view to use the template
  122. git reset --hard exercise09.2 | git show solution09.2 Exercise 9.2

    •Create a template to show the details of a character •Change the character detail view to use the template
  123. git reset --hard exercise09.3 | git show solution09.3 Exercise 9.3

    •Change the character details template to show a character’s inventory
  124. Relations in Templates •When a model object retrieved from the

    ORM has relations, you get a relation manager and not an actual iterable collection •Need to call .all() (or get or filter) on it before you get back the related model objects
  125. Optimizing Queries •Be careful using relations in loops in templates;

    can result in many extra queries •Go read up on: • select_related: does a join in SQL • prefetch_related: queries in advance, caches results, allows “join” in Python
  126. git reset --hard exercise09.4 | git show solution09.4 Exercise 9.4

    •Change the character details view to return a 404 if it can’t find a character
  127. git reset --hard exercise09.5 | git show solution09.5 Exercise 9.5

    •Change the character details view to use the get_object_or_404 shortcut
  128. git reset --hard exercise09.6 | git show solution09.6 Exercise 9.6

    •Change the templates to use dynamically generated URLs in links
  129. git reset --hard exercise09.7 | git show solution09.7 Exercise 9.7

    •Add a namespace to the characters app URLs to prevent collisions with other apps •Update dynamic links in templates to include the namespace
  130. 10. Add a Basic Form to Create Characters

  131. Form Validation •Why? •Classes for each kind of input field

    •Form class to gather input fields •View uses the form class to validate inputs
  132. git reset --hard exercise10.1 | git show solution10.1 Exercise 10.1

    •Create a page with a simple form to create new characters •Just show minimal fields (name, background) for now •Default race and class to the defaults we created earlier •Redirect to the character list
  133. git reset --hard exercise10.2 | git show solution10.2 Exercise 10.2

    •Change how race and class are set to reduce the number of database queries during character creation
  134. Class-Based Views • Separate methods for separate HTTP methods instead

    of conditional logic • Ease development for common cases • Enables advanced designs • Optional; our example code today doesn’t use them
  135. 11. Refactor Views to Reduce Boilerplate

  136. Generic Views •Many views fall into the same patterns •Django

    provides generic view classes for things like showing a list of objects, creating an object, updating an object, deleting, etc. •Subclass and set properties or override certain methods to customize
  137. git reset --hard exercise11.1 | git show solution11.1 Exercise 11.1

    •Change the character list to use a generic ListView •Change the character detail view to use a generic DetailView
  138. git reset --hard exercise11.2 | git show solution11.2 Exercise 11.2

    •Change the character list queryset to order results by character name
  139. git reset --hard exercise11.3 | git show solution11.3 Exercise 11.3

    •Change the character creation view to use a generic CreateView
  140. 12. Make Forms More Efficiently

  141. Model Forms •Forms must declare every field explicitly •ModelForms read

    a model and automatically create the necessary fields •Can quickly customize •Use with caution; exclude fields which should not be visible/editable
  142. git reset --hard exercise12.1 | git show solution12.1 Exercise 12.1

    •Refactor character creation to use a ModelForm
  143. git reset --hard exercise12.2 | git show solution12.2 Exercise 12.2

    •During character creation, only show the fields the user can choose: • name • background • race • class • alignment
  144. git reset --hard exercise12.3 | git show solution12.3 Exercise 12.3

    •Show the stats (strength, dexterity, constitution, intelligence, wisdom, charisma) as read only during character creation •The solution is for illustration only; it has some security issues outside of our scope
  145. 13. Update & Delete Characters

  146. git reset --hard exercise13.1 | git show solution13.1 Exercise 13.1

    •Create a page to update characters using a generic UpdateView
  147. git reset --hard exercise13.2 | git show exercise13.2 Exercise 13.2

    •Create a page to delete characters using a generic DeleteView
  148. 14. User Registration

  149. No Need to Reinvent •Django comes with a robust user

    framework: django.contrib.auth •Registration •Login/Logout •Password Recovery •Etc.
  150. git reset --hard exercise14.1 | git show solution14.1 Exercise 14.1

    •Start a new “accounts” app for managing user accounts
  151. git reset --hard exercise14.2 | git show solution14.2 Exercise 14.2

    •Create a page for registering users •Use django.contrib.auth’s user creation form •Provide our own template and view; base the view on a generic FormView •Don’t forget URLs and settings.py!
  152. The User Object •Always have one in every request •Always

    available to templates •Can be anonymous or populated depending on whether the user has authenticated
  153. git reset --hard exercise14.3 | git show solution14.3 Exercise 14.3

    •Change the character list template •Show the username when signed in •Show the registration link when signed out
  154. 15. User Login & Logout

  155. More Reusable Goodness •django.contrib.auth provides URLs and views for login

    and logout •Will want to provide our own templates
  156. git reset --hard exercise15.1 | git show solution15.1 Exercise 15.1

    •Enable user login and logout •Create templates for login and logged out pages •Use django.contrib.auth views •Link to the login/logout in the character list template •Try it out; what do you observe?
  157. git reset --hard exercise15.2 | git show solution15.2 Exercise 15.2

    •Change the default login redirect URL to the character list page (/characters)
  158. git reset --hard exercise15.3 | git show solution15.3 Exercise 15.3

    •Fix the template resolution order for logout
  159. git reset --hard exercise15.4 | git show solution15.4 Exercise 15.4

    •Create a base template for the site •Change all existing templates to extend the base template •Move the header navigation block (with our login/logout and registration links) to the base template
  160. 16. Let Users OWN Characters

  161. git reset --hard exercise16.1 | git show solution16.1 Exercise 16.1

    •Add a ForeignKey relationship between Characters and Users
  162. git reset --hard exercise16.2 | git show solution16.2 Exercise 16.2

    •Create the migration to add the Character/ User relationship •Run the migration
  163. git reset --hard exercise16.3 | git show solution16.3 Exercise 16.3

    •Add the User that created a Character to the admin fields
  164. git reset --hard exercise16.4 | git show solution16.4 Exercise 16.4

    •Add the player username to the player details page
  165. git reset --hard exercise16.5 | git show solution16.5 Exercise 16.5

    •Require the user to be logged in when creating, editing, or deleting a character
  166. git reset --hard exercise16.6 | git show solution16.6 Exercise 16.6

    •When creating a character, save the user who created the character
  167. 17. Restrict Object Access

  168. Model Managers •A place to encapsulate data queries •Extend to

    provide extra queries with developer-friendly interfaces •Generic views can restrict access by limiting the queryset available in the view
  169. git reset --hard exercise17.1 | git show solution17.1 Exercise 17.1

    •Create a model manager for the Character model •Use the model manager to lock down the edit and delete functions
  170. git reset --hard exercise17.2 | git show solution17.2 Exercise 17.2

    •Remove the edit and delete character links when the user doesn’t own the character
  171. 18. Finishing Touches

  172. git reset --hard exercise18.1 | git show solution18.1 Exercise 18.1

    •Add a basic landing page on the root URL •Include a spiffy logo image
  173. git reset --hard exercise18.1 | git show solution18.2 Exercise 18.2

    •Make sure our pages have awesome branding •Put a small logo on every page
  174. 19. Bonus / Ideas

  175. git reset --hard bonus | git show bonus Bonus Ideas

    •User profiles •Character pictures •Parties (groups of characters) •Rooms/locations •Combat •Loot! •Experience points/ leveling up •Weapons & armor •Race and class, for real •Spells •Multi-classing •REST API
  176. None
  177. A Little Bit About Deployment

  178. Django

  179. Django

  180. Django

  181. Django Django Gunicorn Django or uwsgi!

  182. Django Django Nginx Gunicorn Django or uwsgi!

  183. Django Django Nginx Static Files Gunicorn Django or uwsgi!

  184. Django Django Nginx Static Files Gunicorn Django Varnish or uwsgi!

  185. Where to Deploy •Gondor.io •Heroku •Webfaction •Your favorite VPS (Rackspace,

    AWS, etc.) •Google App Engine (if that’s what you’re into)
  186. Production Advice •Don’t enable admin in production •Don’t enable debug

    in production •Don’t enable the Django Debug Toolbar in production •Don’t publish your production settings & secrets on github
  187. Questions?

  188. Links •http://python.org •https://djangoproject.com •https://github.com/mpirnat/django-tutorial-v2

  189. Credits • Image from Django Unchained by Sony Pictures http://www.nydailynews.com/entertainment/tv-movies/django-star-foxx-life-

    built-race-article-1.1220275 • Image of Django Reinhardt by ~Raimondsy http://raimondsy.deviantart.com/art/Django-Reinhardt-314914547 • Image of Gaming Dice http://www.clker.com/cliparts/R/y/7/z/q/z/role-playing-dice-hi.png • Other images from ClipArt Etc. http://etc.usf.edu/clipart/
  190. Contact Information Mike Pirnat American Greetings http://mike.pirnat.com @mpirnat David Stanek

    Rackspace http://traceback.org @dstanek
  191. Thanks for coming & happy hacking!