#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 [email protected].
To post to this group, send email to [email protected].
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.