Opened 7 years ago

Last modified 5 years ago

#28431 closed Bug

Default value for BinaryField in reverse migration — at Version 1

Reported by: James Owned by: nobody
Component: Core (System checks) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by James)

Description

Initial migration has a default value '' for BinaryField.
Later, change default value to b'' and migrate.
Trying to undo this migration fails. It seems like '' is allowed during migration, but not in reverse migration.

Related issue

#22851 Default value for BinaryField

Reproduce

Python 3.6.0, Django 1.10.6, Postgres 9.5.4

  1. startproject djangoproject
  2. startapp firstapp
  3. firstapp/models.py:
class TableOne(models.Model):
    field1 = models.BinaryField(default = '')
  1. makemigrations firstapp
  2. migrate firstapp 0001
  3. Modify firstapp/models.py
class TableOne(models.Model):
    field1 = models.BinaryField(default = b'')
  1. migrate firstapp 0002
  2. migrate firstapp 0001

Error: TypeError: can't escape str to binary

Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Py\py3_64\lib\site-packages\django\core\management\__init__.py", line 367, in execute_from_command_line
    utility.execute()
  File "C:\Py\py3_64\lib\site-packages\django\core\management\__init__.py", line 359, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Py\py3_64\lib\site-packages\django\core\management\base.py", line 294, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Py\py3_64\lib\site-packages\django\core\management\base.py", line 345, in execute
    output = self.handle(*args, **options)
  File "C:\Py\py3_64\lib\site-packages\django\core\management\commands\migrate.py", line 204, in handle
    fake_initial=fake_initial,
  File "C:\Py\py3_64\lib\site-packages\django\db\migrations\executor.py", line 119, in migrate
    state = self._migrate_all_backwards(plan, full_plan, fake=fake)
  File "C:\Py\py3_64\lib\site-packages\django\db\migrations\executor.py", line 194, in _migrate_all_backwards
    self.unapply_migration(states[migration], migration, fake=fake)
  File "C:\Py\py3_64\lib\site-packages\django\db\migrations\executor.py", line 264, in unapply_migration
    state = migration.unapply(state, schema_editor)
  File "C:\Py\py3_64\lib\site-packages\django\db\migrations\migration.py", line 178, in unapply
    operation.database_backwards(self.app_label, schema_editor, from_state, to_state)
  File "C:\Py\py3_64\lib\site-packages\django\db\migrations\operations\fields.py", line 210, in database_backwards
    self.database_forwards(app_label, schema_editor, from_state, to_state)
  File "C:\Py\py3_64\lib\site-packages\django\db\migrations\operations\fields.py", line 205, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "C:\Py\py3_64\lib\site-packages\django\db\backends\base\schema.py", line 506, in alter_field
    old_db_params, new_db_params, strict)
  File "C:\Py\py3_64\lib\site-packages\django\db\backends\postgresql\schema.py", line 118, in _alter_field
    new_db_params, strict,
  File "C:\Py\py3_64\lib\site-packages\django\db\backends\base\schema.py", line 660, in _alter_field
    params,
  File "C:\Py\py3_64\lib\site-packages\django\db\backends\base\schema.py", line 112, in execute
    cursor.execute(sql, params)
  File "C:\Py\py3_64\lib\site-packages\django\db\backends\utils.py", line 80, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "C:\Py\py3_64\lib\site-packages\django\db\backends\utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
TypeError: can't escape str to binary

Notes

site-packages\django\db\backends\base\shema.py def effective_default(self, field):

determines default as an empty <class 'str'>, when (default = '')

Possible Fix?

site-packages\django\db\backends\base\shema.py ~line 197

def effective_default(self, field):
        if field.has_default():
            default = field.get_default()
            if field.get_internal_type() == "BinaryField" and not default:
                default = six.binary_type()
        elif not field.null and field.blank and field.empty_strings_allowed:
            if field.get_internal_type() == "BinaryField":
                default = six.binary_type()
            else:
                default = six.text_type()
        elif getattr(field, 'auto_now', False)

Change History (1)

comment:1 by James, 7 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top