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

Django Migrations: para entender e perder o medo

Django Migrations: para entender e perder o medo

Presentation at Python Brazil [13]

Kátia Nakamura

October 07, 2017
Tweet

More Decks by Kátia Nakamura

Other Decks in Programming

Transcript

  1. ❖ Django dev na Kiwi.com ❖ Django Girl/PyLady ❖ Viajar

    e fotografar ❖ Pessoas, culturas e lugares pelo mundo @KatiaNakamura Kátia Nakamura
  2. adicionar novos modelos syncdb South: lidar com outros tipos de

    mudanças • alteração • remoção Criado por Andrew Godwin Django < 1.7 @KatiaNakamura
  3. Migrations: lidar com vários tipos de mudanças • adição •

    alteração • remoção • etc. Criado por Andrew Godwin Django >= 1.7 migrate makemigrations sqlmigrate squashmigrations @KatiaNakamura
  4. class Property(models.Model) : price = models.DecimalField( max_digits=15, decimal_places =2) rooms

    = models.PositiveIntegerField() address = models.TextField( null=True, blank=True) city = models.CharField( max_length=255) country = models.CharField( max_length=255) class Meta: abstract = True class House(Property): pass class Apartment(Property): floor = models.PositiveIntegerField() @KatiaNakamura
  5. abstract = True class Property(models.Model): # fields class Meta: abstract

    = True não possui tabela no banco de dados @KatiaNakamura
  6. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py migrate Operations to perform: Apply all

    migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying sessions.0001_initial... OK @KatiaNakamura
  7. makemigrations criar novas migrações baseadas nas mudanças feitas nos modelos

    $ ./manage.py makemigrations [app_name] @KatiaNakamura
  8. class Migration(migrations.Migration): initial = True dependencies = [ ('app', 'migration'),

    ] operations = [ migrations.CreateModel( [...] ), ] @KatiaNakamura
  9. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py makemigrations Migrations for 'core': core/migrations/0001_initial.py -

    Create model Advertiser (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py makemigrations Migrations for 'core': core/migrations/0002_apartment_house.py - Create model Apartment - Create model House (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py makemigrations Migrations for 'core': core/migrations/0003_ad.py - Create model Ad @KatiaNakamura
  10. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py sqlmigrate core 0003 BEGIN; -- --

    Create model Ad -- CREATE TABLE "core_ad" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "status" integer NOT NULL, "published_date" datetime NULL, "object_id" integer unsigned NOT NULL, "ctype_id" integer NOT NULL REFERENCES "django_content_type" ("id"), "owner_id" integer NOT NULL REFERENCES "core_advertiser" ("user_ptr_id")); CREATE INDEX "core_ad_ctype_id_f90eab81" ON "core_ad" ("ctype_id"); CREATE INDEX "core_ad_owner_id_0bb18e6e" ON "core_ad" ("owner_id"); COMMIT; @KatiaNakamura
  11. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py showmigrations admin [X] 0001_initial [X] 0002_logentry_remove_auto_add

    auth [X] 0001_initial [X] 0002_alter_permission_name_max_length [X] 0003_alter_user_email_max_length [X] 0004_alter_user_username_opts [X] 0005_alter_user_last_login_null [X] 0006_require_contenttypes_0002 [X] 0007_alter_validators_add_error_messages [X] 0008_alter_user_username_max_length contenttypes [X] 0001_initial [X] 0002_remove_content_type_name core [ ] 0001_initial [ ] 0002_apartment_house [ ] 0003_ad sessions [X] 0001_initial @KatiaNakamura
  12. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py migrate core Operations to perform: Apply

    all migrations: core Running migrations: Applying core.0001_initial... OK Applying core.0002_apartment_house... OK Applying core.0003_ad... OK (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py migrate core 0002 Operations to perform: Target specific migration: 0002_apartment_house, from core Running migrations: Rendering model states... DONE Unapplying core.0003_ad... OK @KatiaNakamura
  13. class Property(models.Model): price = models.DecimalField(max_digits=15, decimal_places=2) rooms = models.PositiveIntegerField() address

    = models.TextField(null=True, blank=True) state = models.CharField(max_length=255) # city = models.CharField(max_length=255) country = models.CharField(max_length=255) class Meta: abstract = True (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py makemigrations Did you rename apartment.city to apartment.state (a CharField)? [y/N] y Did you rename house.city to house.state (a CharField)? [y/N] y Migrations for 'core': core/migrations/0004_auto_20171006_2348.py - Rename field city on apartment to state - Rename field city on house to state @KatiaNakamura Renomear o campo city para state
  14. class Property(models.Model): price = models.DecimalField(max_digits=15, decimal_places=2) rooms = models.PositiveIntegerField() address

    = models.TextField(null=True, blank=True) state = models.CharField(max_length=255) country = models.CharField(max_length=255) class Meta: abstract = True class House(Property): pass class Apartment(Property): floor = models.PositiveIntegerField() @KatiaNakamura
  15. class Property(models.Model): price = models.DecimalField(max_digits=15, decimal_places=2) rooms = models.PositiveIntegerField() address

    = models.TextField(null=True, blank=True) state = models.CharField(max_length=255) country = models.CharField(max_length=255) class Meta: abstract = True class House(Property): pass class Apartment(House): floor = models.PositiveIntegerField() @KatiaNakamura O que queremos:
  16. class ApartmentOld(Property): floor = models.PositiveIntegerField() (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py makemigrations

    Did you rename the core.Apartment model to ApartmentOld? [y/N] y Migrations for 'core': core/migrations/0005_auto_20171007_0010.py - Rename model Apartment to ApartmentOld @KatiaNakamura 1º passo: Renomear a tabela Apartment para ApartmentOld
  17. class Apartment(House): floor = models.PositiveIntegerField() (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py makemigrations

    Migrations for 'core': core/migrations/0006_apartment.py - Create model Apartment (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py sqlmigrate core 0006 BEGIN; -- -- Create model Apartment -- CREATE TABLE "core_apartment" ("house_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "core_house" ("id"), "floor" integer unsigned NOT NULL); COMMIT; @KatiaNakamura 2º passo: Criar a nova tabela Apartment que herda de House
  18. (.env) Katias-MacBook-Pro:pythonbrazil katia$ python manage.py makemigrations --empty core Migrations for

    'core': core/migrations/0007_auto_20171007_0026.py @KatiaNakamura 3º passo: Criar uma migração vazia e copiar os dados de ApartmentOld para a nova tabela Apartment
  19. # imports def copy_from_to_another(from, to): for obj in from.objects.all(): apt

    = to( price=obj.price, rooms=obj.rooms, address=obj.address, state=obj.state, country=obj.country, floor=obj.floor ) obj.save() to.delete() def update_abs_to_mti(apps, schema_editor): copy_from_to_another( apps.get_model('core', 'ApartmentOld'), apps.get_model('core', 'Apartment') ) def update_mti_to_abs(apps, schema_editor): copy_from_to_another( apps.get_model('core', 'Apartment'), apps.get_model('core', 'ApartmentOld') ) class Migration(migrations.Migration): dependencies = [ ('core', '0006_apartment'), ] operations = [ migrations.RunPython( update_abs_to_mti, update_mti_to_abs ), ] @KatiaNakamura
  20. class House(models.Model): price = models.DecimalField(max_digits=15, decimal_places=2) rooms = models.PositiveIntegerField() address

    = models.TextField(null=True, blank=True) state = models.CharField(max_length=255) country = models.CharField(max_length=255) class Apartment(House): floor = models.PositiveIntegerField() (.env) Katias-MacBook-Pro:pythonbrazil katia$ python manage.py makemigrations Migrations for 'core': core/migrations/0008_delete_apartmentold.py - Delete model ApartmentOld @KatiaNakamura 4º passo: Remover a nova tabela ApartmentOld e remover a classe abstrata Property
  21. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py showmigrations [...] core [X] 0001_initial [X]

    0002_apartment_house [X] 0003_ad [X] 0004_auto_20171006_2348 [X] 0005_auto_20171007_0010 [X] 0006_apartment [X] 0007_auto_20171007_0026 [X] 0008_delete_apartmentold [...] @KatiaNakamura
  22. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py squashmigrations core 0006 Will squash the

    following migrations: - 0001_initial - 0002_apartment_house - 0003_ad - 0004_auto_20171006_2348 - 0005_auto_20171007_0010 - 0006_apartment Do you wish to proceed? [yN] y Optimizing... Optimized from 8 operations to 5 operations. Created new squashed migration /Users/katia/Projects/pythonbrazil/core/migrations/0001_squashed_0006_apartment.py You should commit this migration but leave the old ones in place; the new migration will be used for new installs. Once you are sure all instances of the codebase have applied the migrations you squashed, you can delete them. @KatiaNakamura
  23. class Migration(migrations.Migration) : replaces = [('core', '0001_initial' ), ('core', '0002_apartment_house'

    ), ('core', '0003_ad'), ('core', '0004_auto_20171006_2348' ), ('core', '0005_auto_20171007_0010' ), ('core', '0006_apartment' )] initial = True dependencies = [ ('auth', '0008_alter_user_username_max_length' ), ('contenttypes' , '0002_remove_content_type_name' ), ] operations = [ [...] ] @KatiaNakamura
  24. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py showmigrations admin [X] 0001_initial [X] 0002_logentry_remove_auto_add

    auth [X] 0001_initial [X] 0002_alter_permission_name_max_length [X] 0003_alter_user_email_max_length [X] 0004_alter_user_username_opts [X] 0005_alter_user_last_login_null [X] 0006_require_contenttypes_0002 [X] 0007_alter_validators_add_error_messages [X] 0008_alter_user_username_max_length contenttypes [X] 0001_initial [X] 0002_remove_content_type_name core [X] 0001_squashed_0006_apartment (6 squashed migrations) [X] 0007_auto_20171007_0026 [X] 0008_delete_apartmentold sessions [X] 0001_initial @KatiaNakamura
  25. (.env) Katias-MacBook-Pro:pythonbrazil katia$ ./manage.py migrate Operations to perform: Apply all

    migrations: admin, auth, contenttypes, core, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying core.0001_squashed_0006_apartment... OK Applying core.0007_auto_20171007_0026... OK Applying core.0008_delete_apartmentold... OK Applying sessions.0001_initial... OK @KatiaNakamura Mirgração em um novo banco de dados: