summaryrefslogtreecommitdiff
path: root/django/db
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2014-06-07 17:04:58 -0700
committerAndrew Godwin <andrew@aeracode.org>2014-06-07 17:05:51 -0700
commit6fd455adfcc85f6bd390bce784a1b5dfe5d610ea (patch)
treebbde7ef48977f036461e15a68addc9a3dcdd261e /django/db
parent250e2b422b4da93f38cd61319b9b3c9f422e6ede (diff)
Fixed #22436: More careful checking on method ref'ce serialization
Diffstat (limited to 'django/db')
-rw-r--r--django/db/migrations/writer.py28
1 files changed, 22 insertions, 6 deletions
diff --git a/django/db/migrations/writer.py b/django/db/migrations/writer.py
index f73c4b78a0..d709c91707 100644
--- a/django/db/migrations/writer.py
+++ b/django/db/migrations/writer.py
@@ -12,7 +12,7 @@ import types
from django.apps import apps
from django.db import models
from django.db.migrations.loader import MigrationLoader
-from django.utils import datetime_safe, six
+from django.utils import datetime_safe, six, importlib
from django.utils.encoding import force_text
from django.utils.functional import Promise
@@ -284,13 +284,29 @@ class MigrationWriter(object):
klass = value.__self__
module = klass.__module__
return "%s.%s.%s" % (module, klass.__name__, value.__name__), set(["import %s" % module])
- elif value.__name__ == '<lambda>':
+ # Further error checking
+ if value.__name__ == '<lambda>':
raise ValueError("Cannot serialize function: lambda")
- elif value.__module__ is None:
+ if value.__module__ is None:
raise ValueError("Cannot serialize function %r: No module" % value)
- else:
- module = value.__module__
- return "%s.%s" % (module, value.__name__), set(["import %s" % module])
+ # Python 3 is a lot easier, and only uses this branch if it's not local.
+ if getattr(value, "__qualname__", None) and getattr(value, "__module__", None):
+ if "<" not in value.__qualname__: # Qualname can include <locals>
+ return "%s.%s" % (value.__module__, value.__qualname__), set(["import %s" % value.__module__])
+ # Python 2/fallback version
+ module_name = value.__module__
+ # Make sure it's actually there and not an unbound method
+ module = importlib.import_module(module_name)
+ if not hasattr(module, value.__name__):
+ raise ValueError(
+ "Could not find function %s in %s.\nPlease note that "
+ "due to Python 2 limitations, you cannot serialize "
+ "unbound method functions (e.g. a method declared\n"
+ "and used in the same class body). Please move the "
+ "function into the main module body to use migrations.\n"
+ "For more information, see https://docs.djangoproject.com/en/1.7/topics/migrations/#serializing-values"
+ )
+ return "%s.%s" % (module_name, value.__name__), set(["import %s" % module_name])
# Classes
elif isinstance(value, type):
special_cases = [