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

Upgrading Django (to 1.7)

Andrew Pinkham
September 03, 2014

Upgrading Django (to 1.7)

Slides for my talk at DjangoCon 2014.

Andrew Pinkham

September 03, 2014
Tweet

More Decks by Andrew Pinkham

Other Decks in Technology

Transcript

  1. ANDREW PINKHAM TOPIC DATE AUTHOR SEPTEMBER 2014 UPGRADING DJANGO (TO

    1.7) DJANGOCON 2014 ORIGINAL ART BY ERIK DEPRINCE WALLPAPER CREATED BY BRYAN VELOSO AND CHRISTIAN METTS
 WALLPAPER SITE HOSTED BY JEFF TRIPLETT
  2. $ less updj17 Django Releases Versioning and Support Summary of

    Previous Releases Django 1.7 (v1.6 vs v1.7) Migrations App Loading Static Systems Check
  3. Support Prior to v1.7 ! 1.6.6 1.6.5 1.6.4 1.6.3 …

    1.6
 1.5.9 1.5.8 1.5.7 1.5.6 … 1.5
  4. With Arrival of v1.7 1.7
 1.6.7 1.6.6 1.6.5 1.6.4 …

    1.6
 1.5.10 1.5.9 1.5.8 1.5.7 … 1.5
  5. With Arrival of v1.7 1.7
 1.6.7 1.6.6 1.6.5 1.6.4 …

    1.6
 1.4.15 1.4.14 1.4.13 1.4.12 ! 1.4
  6. Django 1.4 Timezone Support ORM Additions Cookie-Based Session Handling Auth

    Security Functional Browser Testing New Project Creation and Directory Structure
  7. Django 1.5 Python 2.6+ (2.5 Dropped) Experimental Support for Python

    3.2 Custom Django User Generic Class-Based Views JSON
  8. “Django 1.7 is shaping up to be
 the biggest Django

    release since 1.0.” – Russell Keith-Magee
  9. $ django-admin.py startproject camelot # dj16 ! $ django-admin startproject

    camelot # dj17 ! ! ! /manage.py /camelot/ __init__.py settings.py urls.py wsgi.py
  10. # roundtable/models.py ! from django.db import models ! ! !

    ! class Knight(models.Model): name = models.CharField(max_length=63) ! def __str__(self): return self.name
  11. # roundtable/models.py from __future__ import unicode_literals from django.db import models

    from django.utils.encoding import python_2_unicode_compatible ! @python_2_unicode_compatible class Knight(models.Model): name = models.CharField(max_length=63) ! def __str__(self): return self.name
  12. What is a migration? Version Control for you database schema

    Migrations file are instructions for predictably altering the database Change model
 => create migrations file
 => migrate (alter) database
  13. Migrations in 1.6 New Project Recommendations: Create project Add ‘south’,

    to settings.py Start with call to syncdb Create app
  14. $ ./manage.py schemamigration roundtable --initial Creating migrations directory at ‘camelot/

    roundtable/migrations'... Creating __init__.py in 'camelot/roundtable/ migrations'... + Added model roundtable.Knight Created 0001_initial.py. You can now apply this migration with: ./manage.py migrate roundtable
  15. # roundtable/migrations/0001_initial.py # -*- coding: utf-8 -*- from south.utils import

    datetime_utils as datetime from south.db import db from south.v2 import SchemaMigration from django.db import models ! ! class Migration(SchemaMigration): ! def forwards(self, orm): ... def backwards(self, orm): ... models = {...} complete_apps = ['roundtable']
  16. # roundtable/migrations/0001_initial.py from south.db import db ! class Migration(SchemaMigration): !

    def forwards(self, orm): # Adding model 'Knight' db.create_table('roundtable_knight', ( ('id', self.gf('django.db.models.fields.AutoField') (primary_key=True)), ('name', self.gf('django.db.models.fields.CharField') (max_length=63)), )) db.send_create_signal('roundtable', ['Knight'])
  17. # roundtable/migrations/0001_initial.py from south.db import db ! class Migration(SchemaMigration): !

    def backwards(self, orm): # Deleting model 'Knight' db.delete_table('roundtable_knight')
  18. # roundtable/migrations/0001_initial.py class Migration(SchemaMigration): ! models = { 'roundtable.knight': {

    'Meta': {'object_name': 'Knight'}, 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '63'}) } }
  19. $ ./manage.py migrate roundtable 0001 - Soft matched migration 0001

    to 0001_initial. Running migrations for roundtable: - Migrating forwards to 0001_initial. > roundtable:0001_initial - Loading initial data for roundtable. Installed 0 object(s) from 0 fixture(s)
  20. >>> Knight.objects.bulk_create([ ... Knight(name='Bedevere'), ... Knight(name='Bors'), ... Knight(name='Ector'), ... Knight(name='Galahad'),

    ... Knight(name='Gawain'), ... Knight(name='Lancelot'), ... Knight(name='Robin'), ... ]) [<Knight: Bedevere>, <Knight: Bors>, <Knight: Ector>, <Knight: Galahad>, <Knight: Gawain>, <Knight: Lancelot>, <Knight: Robin>]
  21. $ ./manage.py migrate roundtable 0001 - Soft matched migration 0001

    to 0001_initial. Running migrations for roundtable: - Migrating forwards to 0001_initial. > roundtable:0001_initial - Loading initial data for roundtable. Installed 7 object(s) from 1 fixture(s)
  22. # roundtable/models.py from __future__ import unicode_literals from django.db import models

    from django.utils.encoding import python_2_unicode_compatible ! @python_2_unicode_compatible class Knight(models.Model): name = models.CharField(max_length=63) traitor = models.BooleanField() ! def __str__(self): return self.name
  23. # roundtable/migrations/0001_initial.py models = { 'roundtable.knight': { 'Meta': {'object_name': 'Knight'},

    'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '63'}) } }
  24. $ ./manage.py schemamigration roundtable --auto ? The field 'Knight.traitor' does

    not have a default specified, yet is NOT NULL. ? Since you are adding this field, you MUST specify a default ? value to use for existing rows. Would you like to: ? 1. Quit now, and add a default to the field in models.py ? 2. Specify a one-off value to use for existing columns now ? Please select a choice: 2 ? Please enter Python code for your one-off default value. ? The datetime module is available, so you can do e.g. datetime.date.today() >>> False + Added field traitor on roundtable.Knight Created 0002_auto__add_field_knight_traitor.py. You can now apply this migration with:
  25. $ ./manage.py migrate roundtable zero ! $ mv roundtable/fixtures/initial_data.json \

    roundtable/fixtures/0002_add_knight_data.json ! $ ./manage.py migrate roundtable 0001 - Soft matched migration 0001 to 0001_initial. Running migrations for roundtable: - Migrating forwards to 0001_initial. > roundtable:0001_initial - Loading initial data for roundtable. Installed 0 object(s) from 0 fixture(s)
  26. # roundtable/migrations/0002_add_knight_data.py class Migration(DataMigration): ! def forwards(self, orm): "Write your

    forwards methods here." ! def backwards(self, orm): "Write your backwards methods here."
  27. # roundtable/migrations/0002_add_knight_data.py class Migration(SchemaMigration): ! def forwards(self, orm): "Write your

    forwards methods here." from django.core.management import call_command call_command('loaddata', '0002_add_knight_data.json')
  28. # roundtable/migrations/0002_add_knight_data.py class Migration(SchemaMigration): ! def forwards(self, orm): "Write your

    forwards methods here." orm.Knight.objects.bulk_create([ orm.Knight(name='Bedevere'), orm.Knight(name='Bors'), orm.Knight(name='Ector'), orm.Knight(name='Galahad'), orm.Knight(name='Gawain'), orm.Knight(name='Lancelot'), orm.Knight(name='Robin'), ])
  29. $ ./manage.py migrate roundtable zero $ ./manage.py migrate roundtable Running

    migrations for roundtable: - Migrating forwards to 0002_add_knight_data. > roundtable:0001_initial > roundtable:0002_add_knight_data - Migration 'roundtable:0002_add_knight_data' is marked for no-dry-run. - Loading initial data for roundtable. Installed 0 object(s) from 0 fixture(s)
  30. $ ./manage.py migrate roundtable 0001 - Soft matched migration 0001

    to 0001_initial. Running migrations for roundtable: - Migrating backwards to just after 0001_initial. < roundtable:0002_add_knight_data - Migration 'roundtable:0002_add_knight_data' is marked for no-dry-run.
  31. $ ./manage.py schemamigration roundtable --auto ? The field 'Knight.traitor' does

    not have a default specified, yet is NOT NULL. ? Since you are adding this field, you MUST specify a default ? value to use for existing rows. Would you like to: ? 1. Quit now, and add a default to the field in models.py ? 2. Specify a one-off value to use for existing columns now ? Please select a choice: 2 ? Please enter Python code for your one-off default value. ? The datetime module is available, so you can do e.g. datetime.date.today() >>> False + Added field traitor on roundtable.Knight Created 0003_auto__add_field_knight_traitor.py. You can now apply this migration with: ./manage.py migrate roundtable
  32. $ ./manage.py migrate roundtable Running migrations for roundtable: - Migrating

    forwards to 0003_auto__add_field_knight_traitor. > roundtable:0002_add_knight_data - Migration 'roundtable:0002_add_knight_data' is marked for no-dry-run. > roundtable:0003_auto__add_field_knight_traitor - Loading initial data for roundtable. Installed 0 object(s) from 0 fixture(s)
  33. # roundtable/migrations/0004_label_lancelot_traitor.py class Migration(DataMigration): ! def forwards(self, orm): lancelot =

    orm.Knight.objects.get( name__iexact="Lancelot") lancelot.traitor = True lancelot.save()
  34. # roundtable/migrations/0004_label_lancelot_traitor.py class Migration(DataMigration): ! def backwards(self, orm): lancelot =

    orm.Knight.objects.get( name__iexact="Lancelot") lancelot.traitor = False lancelot.save()
  35. $ ./manage.py migrate roundtable Running migrations for roundtable: - Migrating

    forwards to 0004_label_lancelot_traitor. > roundtable:0004_label_lancelot_traitor - Migration 'roundtable: 0004_label_lancelot_traitor' is marked for no-dry- run. - Loading initial data for roundtable. Installed 0 object(s) from 0 fixture(s)
  36. # roundtable/models.py from __future__ import unicode_literals from django.db import models

    from django.utils.encoding import python_2_unicode_compatible ! @python_2_unicode_compatible class Knight(models.Model): name = models.CharField(max_length=63) ! def __str__(self): return self.name
  37. # roundtable/migrations/0001_initial.py # -*- coding: utf-8 -*- from __future__ import

    unicode_literals from django.db import models, migrations ! ! class Migration(migrations.Migration): ! dependencies = [] operations = [...]
  38. # roundtable/migrations/0001_initial.py class Migration(migrations.Migration): ! operations = [ migrations.CreateModel( name='Knight',

    fields=[ ('id', models.AutoField( primary_key=True, verbose_name='ID', serialize=False, auto_created=True)), ('name', models.CharField( max_length=63)), ], options={}, bases=(models.Model,), ), ]
  39. $ ./manage.py migrate Operations to perform: Apply all migrations: auth,

    admin, contenttypes, roundtable, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying roundtable.0001_initial... OK Applying sessions.0001_initial... OK
  40. # roundtable/migrations/0002_auto_add_knight_data.py ! ! ! ! ! ! ! !

    ! class Migration(migrations.Migration): ... operations = [ ! ! ! ]
  41. # roundtable/migrations/0002_auto_add_knight_data.py ! def add_knight_data(apps, schema_editor): pass ! ! def

    remove_knight_data(apps, schema_editor): pass ! ! class Migration(migrations.Migration): ... operations = [ migrations.RunPython( add_knight_data, reverse_code=remove_knight_data), ]
  42. # roundtable/migrations/0002_auto_add_knight_data.py def add_knight_data(apps, schema_editor): Knight = apps.get_model('roundtable', 'Knight') Knight.objects.bulk_create([

    Knight(name='Bedevere'), Knight(name='Bors'), Knight(name='Ector'), Knight(name='Galahad'), Knight(name='Gawain'), Knight(name='Lancelot'), Knight(name='Robin'), ])
  43. # roundtable/models.py from __future__ import unicode_literals from django.db import models

    from django.utils.encoding import python_2_unicode_compatible ! @python_2_unicode_compatible class Knight(models.Model): name = models.CharField(max_length=63) traitor = models.BooleanField() ! def __str__(self): return self.name
  44. $ ./manage.py check System check identified some issues: ! WARNINGS:

    roundtable.Knight.traitor: (1_6.W002) BooleanField does not have a default value. HINT: Django 1.6 changed the default value of BooleanField from False to None. See [DOCS LINK] for more information. ! System check identified 1 issue (0 silenced).
  45. $ ./manage.py makemigrations System check identified some issues: ! WARNINGS:

    [Removed from Slides] You are trying to add a non-nullable field 'traitor' to knight without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows) 2) Quit, and let me add a default in models.py Select an option: 1 Please enter the default value now, as valid Python The datetime module is available, so you can do e.g. datetime.date.today()
  46. $ ./manage.py migrate System check identified some issues: ! WARNINGS:

    roundtable.Knight.traitor: (1_6.W002) BooleanField does not have a default value. HINT: Django 1.6 changed the default value of BooleanField from False to None. See [DOCS LINK] for more information. Operations to perform: Apply all migrations: auth, sessions, admin, roundtable, contenttypes Running migrations: Applying roundtable.0003_knight_traitor... OK
  47. # roundtable/models.py from __future__ import unicode_literals from django.db import models

    from django.utils.encoding import python_2_unicode_compatible ! @python_2_unicode_compatible class Knight(models.Model): name = models.CharField(max_length=63) traitor = models.BooleanField(default=False) ! def __str__(self): return self.name
  48. # roundtable/migrations/0004_label_lancelot_traitor.py # -*- coding: utf-8 -*- from __future__ import

    unicode_literals from django.db import models, migrations ! ... ! class Migration(migrations.Migration): ! dependencies = [ ('roundtable', '0003_knight_traitor'), ] ! operations = [ migrations.RunPython( set_lancelot_traitor, reverse_code=unset_lancelot_traitor) ]
  49. Migrations in 1.7 Historical Model built and kept in memory

    Integrated with App Loader Utility of Dependency Caveat: Python Classes do not serialize!
 ModelA.save() will not be called. May be slow…
  50. South will NOT run in 1.7 Upgrade from South: Latest

    Migration Create Native Delete South Settings: MIGRATION_MODULES and SOUTH_MIGRATION_MODULES South and 1.7
  51. New App Registry Allow apps without a models module or

    package apps.get_model() app/apps.py Calls made in AppConfig admin.autodiscover()
  52. Systems Check check in 1.6 verified settings response to 1.5

    upgrade now extendable and modular validate deprecated (avoid confusion with field and forms use check
  53. 1.0 1.1 1.2 1.3 1.4 1.5 1.6 R² = 0.8733

    190d 253d 340d 366d 310d 292d 329d Duration Until Next Release Polynomial Regression (Order 3) Expected
  54. 1.0 1.1 1.2 1.3 1.4 1.5 1.6 R² = 0.1971

    300d 253d 340d 366d 310d 292d 329d Duration Until Next Release Polynomial Regression (Order 3) Actual
  55. Practical Knowledge Django 1.7 means death of 1.5 Django 1.5

    has not been added to LTS support Django 1.4 has less than a year of support Migrate to Django 1.6 now
  56. Practical Upgrade Knowledge Iterate Through Versions Password Gotcha: base36 (1.5)

    -> base64 (1.6) syncdb is dead. Long live migrate Initial data fixtures are dead.
 Long live data migrations. Fields need deconstruct()
  57. The Future? LTS Status for 1.8? Look ahead at deprecations

    URL Configurations lists no patterns direct imports