Fixed #21290: Documented migration serializing and improved error

This commit is contained in:
Andrew Godwin 2014-01-19 19:27:10 +00:00
parent 34263c67b4
commit 6bbb820014
2 changed files with 59 additions and 1 deletions

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import datetime import datetime
import inspect import inspect
import decimal
from importlib import import_module from importlib import import_module
import os import os
import types import types
@ -221,6 +222,9 @@ class MigrationWriter(object):
# Promise # Promise
elif isinstance(value, Promise): elif isinstance(value, Promise):
return repr(force_text(value)), set() return repr(force_text(value)), set()
# Decimal
elif isinstance(value, decimal.Decimal):
return repr(value), set(["from decimal import Decimal"])
# Django fields # Django fields
elif isinstance(value, models.Field): elif isinstance(value, models.Field):
attr_name, path, args, kwargs = value.deconstruct() attr_name, path, args, kwargs = value.deconstruct()
@ -255,7 +259,7 @@ class MigrationWriter(object):
return "%s.%s" % (module, value.__name__), set(["import %s" % module]) return "%s.%s" % (module, value.__name__), set(["import %s" % module])
# Uh oh. # Uh oh.
else: else:
raise ValueError("Cannot serialize: %r" % value) raise ValueError("Cannot serialize: %r\nThere are some values Django cannot serialize into migration files.\nFor more, see https://docs.djangoproject.com/en/dev/topics/migrations/#migration-serializing" % value)
MIGRATION_TEMPLATE = """\ MIGRATION_TEMPLATE = """\

View File

@ -281,6 +281,7 @@ Note that this only works given two things:
that your database doesn't match your models, you'll just get errors when that your database doesn't match your models, you'll just get errors when
migrations try to modify those tables. migrations try to modify those tables.
.. _historical-models: .. _historical-models:
Historical models Historical models
@ -302,3 +303,56 @@ so you must always keep base classes around for as long as there is a migration
that contains a reference to them. On the plus side, methods and managers that contains a reference to them. On the plus side, methods and managers
from these base classes inherit normally, so if you absolutely need access from these base classes inherit normally, so if you absolutely need access
to these you can opt to move them into a superclass. to these you can opt to move them into a superclass.
.. _migration-serializing:
Serializing values
------------------
Migrations are just Python files containing the old definitions of your models
- thus, to write them, Django must take the current state of your models and
serialize them out into a file.
While Django can serialize most things, there are some things that we just
can't serialize out into a valid Python representation - there's no Python
standard for how a value can be turned back into code (``repr()`` only works
for basic values, and doesn't specify import paths).
Django can serialize the following:
- ``int``, ``long``, ``float``, ``bool``, ``str``, ``unicode``, ``bytes``, ``None``
- ``list``, ``set``, ``tuple``, ``dict``
- ``datetime.date`` and ``datetime.datetime`` instances
- ``decimal.Decimal`` instances
- Any Django field
- Any function or method reference (e.g. ``datetime.datetime.today``)
- Any class reference
- Anything with a custom ``deconstruct()`` method (:ref:`see below <custom-deconstruct-method>`)
Django cannot serialize:
- Arbitrary class instances (e.g. ``MyClass(4.3, 5.7)``)
- Lambdas
.. _custom-deconstruct-method:
Adding a deconstruct() method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can let Django serialize your own custom class instances by giving the class
a ``deconstruct`` method. It takes no arguments, and should return a tuple
of 3 things: ``(path, args, kwargs)``.
``path`` should be the Python path to the class, with the class name included as the
last part (for example, ``myapp.custom_things.MyClass``). If your class is not
available at the top level of a module it is not serializable.
``args`` should be a list of positional arguments to pass to your class'
``__init__`` method. Everything in this list should itself be serializable.
``kwargs`` should be a dict of keyword arguments to pass to your class'
``__init__`` method. Every value should itself be serializable.
Django will write out the value as an instatiation of your class with the
given arguments, similar to the way it writes out references to Django fields.