diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py index d24a37e5b90..4f65a12c6d2 100644 --- a/django/db/migrations/state.py +++ b/django/db/migrations/state.py @@ -207,6 +207,8 @@ class ModelState(object): options[name] = set(normalize_together(it)) else: options[name] = model._meta.original_attrs[name] + # Force-convert all options to text_type (#23226) + options = cls.force_text_recursive(options) # If we're ignoring relationships, remove all field-listing model # options (that option basically just means "make a stub model") if exclude_rels: @@ -250,6 +252,23 @@ class ModelState(object): bases, ) + @classmethod + def force_text_recursive(cls, value): + if isinstance(value, six.string_types): + return six.text_type(value) + elif isinstance(value, list): + return [cls.force_text_recursive(x) for x in value] + elif isinstance(value, tuple): + return tuple(cls.force_text_recursive(x) for x in value) + elif isinstance(value, set): + return set(cls.force_text_recursive(x) for x in value) + elif isinstance(value, dict): + return dict( + (cls.force_text_recursive(k), cls.force_text_recursive(v)) + for k, v in value.items() + ) + return value + def construct_fields(self): "Deep-clone the fields using deconstruction" for name, field in self.fields: