Opened 2 years ago

Closed 2 years ago

#20977 closed Bug (fixed)

Encoding error writing new migrations on Python 3

Reported by: MarkusH Owned by: MarkusH
Component: Migrations Version: master
Severity: Normal Keywords:
Cc: info@… Triage Stage: Accepted
Has patch: no Needs documentation: yes
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When trying to create a migration using Python 3 I get the following error:

$ python manage.py makemigrations something -v3
Migrations for 'something':
  0001_initial.py:
    - Create model MyModel
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/__init__.py", line 397, in execute_from_command_line
    utility.execute()
  File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/__init__.py", line 390, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/base.py", line 242, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/base.py", line 289, in execute
    output = self.handle(*args, **options)
  File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/commands/makemigrations.py", line 86, in handle
    fh.write(writer.as_string())
TypeError: must be str, not bytes

I got this fixed by a small change:

diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py
index d802e29..a0befaa 100644
--- a/django/core/management/commands/makemigrations.py
+++ b/django/core/management/commands/makemigrations.py
@@ -80,5 +80,5 @@ class Command(BaseCommand):
                         open(init_path, "w").close()
                     # We just do this once per app
                     directory_created[app_label] = True
-                with open(writer.path, "w") as fh:
+                with open(writer.path, "wb") as fh:
                     fh.write(writer.as_string())

However, given this models.py, I get different migration files depending of the Python version I use to create the migration:

# -*- coding: utf-8 -*-
from django.db import models
from django.utils.encoding import python_2_unicode_compatible


@python_2_unicode_compatible
class MyModel(models.Model):
    name = models.CharField('Name', max_length=50, unique=True)
    text = models.TextField('Text', blank=True, null=True)

    class Meta:
        verbose_name = 'My “fancy” Model'
        verbose_name_plural = 'My “fancy” Models'

    def __str__(self):
        return self.name

The migration file for Python 3:

# encoding: utf8
from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = []

    operations = [
        migrations.CreateModel(
            options = {'verbose_name_plural': 'My “fancy” Models', 'verbose_name': 'My “fancy” Model'},
            bases = (models.Model,),
            name = 'MyModel',
            fields = [('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID'),), ('name', models.CharField(max_length=50, verbose_name='Name', unique=True),), ('text', models.TextField(blank=True, verbose_name='Text', null=True),)],
        ),
    ]

The migration file for Python 2:

# encoding: utf8
from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = []

    operations = [
        migrations.CreateModel(
            fields = [(u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True),), ('name', models.CharField(unique=True, max_length=50, verbose_name='Name'),), ('text', models.TextField(null=True, verbose_name='Text', blank=True),)],
            bases = (models.Model,),
            options = {u'verbose_name': 'My \xe2\x80\x9cfancy\xe2\x80\x9d Model', u'verbose_name_plural': 'My \xe2\x80\x9cfancy\xe2\x80\x9d Models'},
            name = 'MyModel',
        ),
    ]

Note the differences for the "options":

options = {'verbose_name_plural': 'My “fancy” Models', 'verbose_name': 'My “fancy” Model'},

vs

options = {u'verbose_name': 'My \xe2\x80\x9cfancy\xe2\x80\x9d Model', u'verbose_name_plural': 'My \xe2\x80\x9cfancy\xe2\x80\x9d Models'},

As far as I have tested, this does not make a problem when using the other Python version to apply the migration.

Change History (4)

comment:1 Changed 2 years ago by timo

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

comment:2 Changed 2 years ago by MarkusH

  • Needs documentation set
  • Owner set to MarkusH
  • Status changed from new to assigned

comment:3 Changed 2 years ago by MarkusH

  • Cc info@… added

comment:4 Changed 2 years ago by Tim Graham <timograham@…>

  • Resolution set to fixed
  • Status changed from assigned to closed

In bd8e1a354cb1fde5e5411e3c729a0d179f4eb37b:

Fixed #20977 -- Fixed writing migrations to disk on Python 3

Note: See TracTickets for help on using tickets.
Back to Top