Opened 7 years ago
Last modified 6 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 )
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
- startproject djangoproject
- startapp firstapp
- firstapp/models.py:
class TableOne(models.Model): field1 = models.BinaryField(default = '')
- makemigrations firstapp
- migrate firstapp 0001
- Modify firstapp/models.py
class TableOne(models.Model): field1 = models.BinaryField(default = b'')
- migrate firstapp 0002
- 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)