You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

58 lines
2.0 KiB

  1. from importlib import import_module
  2. from django.utils.version import get_docs_version
  3. def deconstructible(*args, **kwargs):
  4. """
  5. Class decorator that allow the decorated class to be serialized
  6. by the migrations subsystem.
  7. Accepts an optional kwarg `path` to specify the import path.
  8. """
  9. path = kwargs.pop('path', None)
  10. def decorator(klass):
  11. def __new__(cls, *args, **kwargs):
  12. # We capture the arguments to make returning them trivial
  13. obj = super(klass, cls).__new__(cls)
  14. obj._constructor_args = (args, kwargs)
  15. return obj
  16. def deconstruct(obj):
  17. """
  18. Returns a 3-tuple of class import path, positional arguments,
  19. and keyword arguments.
  20. """
  21. # Python 2/fallback version
  22. if path:
  23. module_name, _, name = path.rpartition('.')
  24. else:
  25. module_name = obj.__module__
  26. name = obj.__class__.__name__
  27. # Make sure it's actually there and not an inner class
  28. module = import_module(module_name)
  29. if not hasattr(module, name):
  30. raise ValueError(
  31. "Could not find object %s in %s.\n"
  32. "Please note that you cannot serialize things like inner "
  33. "classes. Please move the object into the main module "
  34. "body to use migrations.\n"
  35. "For more information, see "
  36. "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values"
  37. % (name, module_name, get_docs_version()))
  38. return (
  39. path or '%s.%s' % (obj.__class__.__module__, name),
  40. obj._constructor_args[0],
  41. obj._constructor_args[1],
  42. )
  43. klass.__new__ = staticmethod(__new__)
  44. klass.deconstruct = deconstruct
  45. return klass
  46. if not args:
  47. return decorator
  48. return decorator(*args, **kwargs)