PageRenderTime 26ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/python/lib/django-1.2/django/db/models/fields/subclassing.py

https://gitlab.com/gregtyka/frankenserver
Python | 117 lines | 94 code | 7 blank | 16 comment | 14 complexity | 701828d7c06e3e8c456a1d19234e4b47 MD5 | raw file
  1. """
  2. Convenience routines for creating non-trivial Field subclasses, as well as
  3. backwards compatibility utilities.
  4. Add SubfieldBase as the __metaclass__ for your Field subclass, implement
  5. to_python() and the other necessary methods and everything will work seamlessly.
  6. """
  7. from inspect import getargspec
  8. from warnings import warn
  9. def call_with_connection(func):
  10. arg_names, varargs, varkwargs, defaults = getargspec(func)
  11. updated = ('connection' in arg_names or varkwargs)
  12. if not updated:
  13. warn("A Field class whose %s method hasn't been updated to take a "
  14. "`connection` argument." % func.__name__,
  15. PendingDeprecationWarning, stacklevel=2)
  16. def inner(*args, **kwargs):
  17. if 'connection' not in kwargs:
  18. from django.db import connection
  19. kwargs['connection'] = connection
  20. warn("%s has been called without providing a connection argument. " %
  21. func.__name__, PendingDeprecationWarning,
  22. stacklevel=1)
  23. if updated:
  24. return func(*args, **kwargs)
  25. if 'connection' in kwargs:
  26. del kwargs['connection']
  27. return func(*args, **kwargs)
  28. return inner
  29. def call_with_connection_and_prepared(func):
  30. arg_names, varargs, varkwargs, defaults = getargspec(func)
  31. updated = (
  32. ('connection' in arg_names or varkwargs) and
  33. ('prepared' in arg_names or varkwargs)
  34. )
  35. if not updated:
  36. warn("A Field class whose %s method hasn't been updated to take "
  37. "`connection` and `prepared` arguments." % func.__name__,
  38. PendingDeprecationWarning, stacklevel=2)
  39. def inner(*args, **kwargs):
  40. if 'connection' not in kwargs:
  41. from django.db import connection
  42. kwargs['connection'] = connection
  43. warn("%s has been called without providing a connection argument. " %
  44. func.__name__, PendingDeprecationWarning,
  45. stacklevel=1)
  46. if updated:
  47. return func(*args, **kwargs)
  48. if 'connection' in kwargs:
  49. del kwargs['connection']
  50. if 'prepared' in kwargs:
  51. del kwargs['prepared']
  52. return func(*args, **kwargs)
  53. return inner
  54. class LegacyConnection(type):
  55. """
  56. A metaclass to normalize arguments give to the get_db_prep_* and db_type
  57. methods on fields.
  58. """
  59. def __new__(cls, name, bases, attrs):
  60. new_cls = super(LegacyConnection, cls).__new__(cls, name, bases, attrs)
  61. for attr in ('db_type', 'get_db_prep_save'):
  62. setattr(new_cls, attr, call_with_connection(getattr(new_cls, attr)))
  63. for attr in ('get_db_prep_lookup', 'get_db_prep_value'):
  64. setattr(new_cls, attr, call_with_connection_and_prepared(getattr(new_cls, attr)))
  65. return new_cls
  66. class SubfieldBase(LegacyConnection):
  67. """
  68. A metaclass for custom Field subclasses. This ensures the model's attribute
  69. has the descriptor protocol attached to it.
  70. """
  71. def __new__(cls, name, bases, attrs):
  72. new_class = super(SubfieldBase, cls).__new__(cls, name, bases, attrs)
  73. new_class.contribute_to_class = make_contrib(
  74. new_class, attrs.get('contribute_to_class')
  75. )
  76. return new_class
  77. class Creator(object):
  78. """
  79. A placeholder class that provides a way to set the attribute on the model.
  80. """
  81. def __init__(self, field):
  82. self.field = field
  83. def __get__(self, obj, type=None):
  84. if obj is None:
  85. raise AttributeError('Can only be accessed via an instance.')
  86. return obj.__dict__[self.field.name]
  87. def __set__(self, obj, value):
  88. obj.__dict__[self.field.name] = self.field.to_python(value)
  89. def make_contrib(superclass, func=None):
  90. """
  91. Returns a suitable contribute_to_class() method for the Field subclass.
  92. If 'func' is passed in, it is the existing contribute_to_class() method on
  93. the subclass and it is called before anything else. It is assumed in this
  94. case that the existing contribute_to_class() calls all the necessary
  95. superclass methods.
  96. """
  97. def contribute_to_class(self, cls, name):
  98. if func:
  99. func(self, cls, name)
  100. else:
  101. super(superclass, self).contribute_to_class(cls, name)
  102. setattr(cls, self.name, Creator(self))
  103. return contribute_to_class