#31245 closed Bug (invalid)
CharField doesn't accept bytestrings in default parameter in Django 2.2.
Reported by: | Tony S Yu | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 2.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
System details
- Migrations generated in Django 1.11.28 + Python 2.7
- Migrations run on Django 2.2.10 + Python 3.6
- Database backend:
django.db.backends.mysql
Summary
We recently upgraded an app from Django 1.11 to 2.2. When a developer on the team attempted to re-install the app from scratch some time later, they ran into the following exception:
django.db.utils.OperationalError: (1067, "Invalid default value for '<charfield>'")
where the <charfield>
had choices
containing bytestring db values and unicode string labels (i.e. choices=[(<bytes>, <str>),...]
)
I reproduced this in isolation using a modified version of the Students example from the docs:
class Student(models.Model): name = models.CharField(max_length=300) FRESHMAN = 'FR' SOPHOMORE = 'SO' JUNIOR = 'JR' SENIOR = 'SR' GRADUATE = 'GR' YEAR_IN_SCHOOL_CHOICES = [ (FRESHMAN, u'Freshman'), (SOPHOMORE, u'Sophomore'), (JUNIOR, u'Junior'), (SENIOR, u'Senior'), (GRADUATE, u'Graduate'), ] year_in_school = models.CharField( max_length=2, choices=YEAR_IN_SCHOOL_CHOICES, default=FRESHMAN, )
The main modification is that the choices
labels are explicitly unicode, but the db values are unprefixed strings (bytestrings in Python 2, unicode in Python 3). (Note that the actual code generated choices from an Enum
, which when combined with Python 2 using unicode literals causes bytestring db values and unicode labels used above.)
In practice, I wasn't able to reproduce the error without splitting up the year_in_school
migration from the model creation. (The name
field was added to the model to create an initial migration.)
Running the year_in_school
migration using Django 1.11.28 (on Python 2.7) generates the following migration:
# -*- coding: utf-8 -*- # Generated by Django 1.11.28 on 2020-02-07 17:07 from __future__ import unicode_literals from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('djangodebug', '0001_initial'), ] operations = [ migrations.AddField( model_name='student', name='year_in_school', field=models.CharField(choices=[(b'FR', 'Freshman'), (b'SO', 'Sophomore'), (b'JR', 'Junior'), (b'SR', 'Senior'), (b'GR', 'Graduate')], default=b'FR', max_length=2), ), ]
Running that migration in Django 1.11 (on either Python 2 or 3) works fine. Running the migration in Django 2.2 throws the following error:
django.db.utils.OperationalError: (1067, "Invalid default value for 'year_in_school'")
Additional Notes
Workarounds
- Downgrade to Django 1.11 and run migrations, then revert to Django 2.2
- Manually modify migration files to use unicode strings (i.e. remove
b
prefix from strings)
Change History (2)
comment:1 by , 5 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Resolution: | → invalid |
Status: | new → closed |
Summary: | "Invalid default value for '<charfield>'" for CharField choices migration generated by Django 1.11 and run on Django 2.2 → CharField doesn't accept bytestrings in default parameter in Django 2.2. |
comment:2 by , 5 years ago
That makes sense. I was working under the (baseless) assumption that migrations would remain backwards compatible (which I recognize would be a huge burden). After your comment, I did find other notes in the docs about the need for editing old migrations files to add on_delete, so my assumption was obviously wrong. Thanks
Support for
bytestring
was removed in some places in Django 2.0 (see release notes).