#27378: makemigration unable to serialize UUID when UUIDField have choices set -----------------------------+------------------------------------ Reporter: make.kernel | Owner: nobody Type: Bug | Status: new Component: Migrations | Version: 1.10 Severity: Normal | Keywords: uuid choices migration Triage Stage: Unreviewed | Has patch: 1 Easy pickings: 0 | UI/UX: 0 -----------------------------+------------------------------------ Using following model
{{{ import uuid from django.db import models # Create your models here. class Student(models.Model): FRESHMAN = uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8') SOPHOMORE = uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2') JUNIOR = uuid.UUID('94a43637-6dfc-4209-852a-bd9bd8c0101f') SENIOR = uuid.UUID('dfb9cc50-c332-4809-9b4c-69c81a7489d0') MENTOR = uuid.UUID('b8f3897a-0a0a-4630-8f1b-1ca4b0ee37ca') YEAR_IN_SCHOOL_CHOICES = ( (FRESHMAN, 'Freshman'), (SOPHOMORE, 'Sophomore'), (JUNIOR, 'Junior'), (SENIOR, 'Senior'), (MENTOR, 'Mentor'), ) year_in_school = models.UUIDField(choices=YEAR_IN_SCHOOL_CHOICES, default=FRESHMAN) }}} According to documentation it should work, and it works until you try to make migrations for this model, it fails with exception {{{ Migrations for 'testapp': testapp/migrations/0001_initial.py: - Create model Student Traceback (most recent call last): File "./manage.py", line 22, in <module> execute_from_command_line(sys.argv) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/core/management/__init__.py", line 367, in execute_from_command_line utility.execute() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/core/management/__init__.py", line 359, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/core/management/base.py", line 294, in run_from_argv self.execute(*args, **cmd_options) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/core/management/base.py", line 345, in execute output = self.handle(*args, **options) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/core/management/commands/makemigrations.py", line 189, in handle self.write_migration_files(changes) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/core/management/commands/makemigrations.py", line 224, in write_migration_files migration_string = writer.as_string() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/writer.py", line 163, in as_string operation_string, operation_imports = OperationWriter(operation).serialize() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/writer.py", line 120, in serialize _write(arg_name, arg_value) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/writer.py", line 84, in _write arg_string, arg_imports = MigrationWriter.serialize(_arg_value) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/writer.py", line 293, in serialize return serializer_factory(value).serialize() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/serializer.py", line 228, in serialize return self.serialize_deconstructed(path, args, kwargs) File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/serializer.py", line 100, in serialize_deconstructed arg_string, arg_imports = serializer_factory(arg).serialize() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/serializer.py", line 43, in serialize item_string, item_imports = serializer_factory(item).serialize() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/serializer.py", line 43, in serialize item_string, item_imports = serializer_factory(item).serialize() File "/home/yuriy/dev/uuidtest/env/lib/python3.5/site- packages/django/db/migrations/serializer.py", line 388, in serializer_factory "topics/migrations/#migration-serializing" % (value, get_docs_version()) ValueError: Cannot serialize: UUID('5c859437-d061-4847-b3f7-e6b78852f8c8') There are some values Django cannot serialize into migration files. For more, see https://docs.djangoproject.com/en/1.10/topics/migrations /#migration-serializing }}} Here is a small patch that add UUIDSerializer to migration serializers and tells serializer_factory to use it in case of UUID value {{{ --- django/db/migrations/serializer.py.orig 2016-10-24 12:16:21.000000000 +0300 +++ django/db/migrations/serializer.py 2016-10-24 15:32:33.908818046 +0300 @@ -6,6 +6,7 @@ import functools import math import types +import uuid from importlib import import_module from django.db import models @@ -319,6 +320,10 @@ else: return "%s.%s" % (module, self.value.__name__), {"import %s" % module} +class UUIDSerializer(BaseSerializer): + def serialize(self): + return "uuid.UUID('%s')" % self.value, {"import uuid"} + def serializer_factory(value): from django.db.migrations.writer import SettingsReference @@ -382,6 +387,8 @@ return IterableSerializer(value) if isinstance(value, (COMPILED_REGEX_TYPE, RegexObject)): return RegexSerializer(value) + if isinstance(value, uuid.UUID): + return UUIDSerializer(value) raise ValueError( "Cannot serialize: %r\nThere are some values Django cannot serialize into " "migration files.\nFor more, see https://docs.djangoproject.com/en/%s/" }}} After applying this change everything works as expected {{{ (env) yuriy@yuriy-desktop:~/dev/uuidtest/src/uuidtest$ ./manage.py makemigrations Migrations for 'testapp': testapp/migrations/0001_initial.py: - Create model Student (env) yuriy@yuriy-desktop:~/dev/uuidtest/src/uuidtest$ ./manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, testapp Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying sessions.0001_initial... OK Applying testapp.0001_initial... OK (env) yuriy@yuriy-desktop:~/dev/uuidtest/src/uuidtest$ }}} migratin produced is {{{ # -*- coding: utf-8 -*- # Generated by Django 1.10.2 on 2016-10-24 13:30 from __future__ import unicode_literals from django.db import migrations, models import uuid class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Student', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('year_in_school', models.UUIDField(choices=[(uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8'), 'Freshman'), (uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2'), 'Sophomore'), (uuid.UUID('94a43637-6dfc-4209-852a-bd9bd8c0101f'), 'Junior'), (uuid.UUID('dfb9cc50-c332-4809-9b4c-69c81a7489d0'), 'Senior'), (uuid.UUID('b8f3897a-0a0a-4630-8f1b-1ca4b0ee37ca'), 'Mentor')], default=uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8'))), ], ), ] }}} I have no idea if it is correct, but works for me, if it should be fixed in other place could you point me where to look? Thanks -- Ticket URL: <https://code.djangoproject.com/ticket/27378> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/054.e1b0e6965f5b9bbabc07d774963b49d0%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.