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.

subclassing.py 2.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  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
  6. seamlessly.
  7. """
  8. import warnings
  9. from django.utils.deprecation import RemovedInDjango110Warning
  10. class SubfieldBase(type):
  11. """
  12. A metaclass for custom Field subclasses. This ensures the model's attribute
  13. has the descriptor protocol attached to it.
  14. """
  15. def __new__(cls, name, bases, attrs):
  16. warnings.warn("SubfieldBase has been deprecated. Use Field.from_db_value instead.",
  17. RemovedInDjango110Warning, stacklevel=2)
  18. new_class = super(SubfieldBase, cls).__new__(cls, name, bases, attrs)
  19. new_class.contribute_to_class = make_contrib(
  20. new_class, attrs.get('contribute_to_class')
  21. )
  22. return new_class
  23. class Creator(object):
  24. """
  25. A placeholder class that provides a way to set the attribute on the model.
  26. """
  27. def __init__(self, field):
  28. self.field = field
  29. def __get__(self, obj, type=None):
  30. if obj is None:
  31. return self
  32. return obj.__dict__[self.field.name]
  33. def __set__(self, obj, value):
  34. obj.__dict__[self.field.name] = self.field.to_python(value)
  35. def make_contrib(superclass, func=None):
  36. """
  37. Returns a suitable contribute_to_class() method for the Field subclass.
  38. If 'func' is passed in, it is the existing contribute_to_class() method on
  39. the subclass and it is called before anything else. It is assumed in this
  40. case that the existing contribute_to_class() calls all the necessary
  41. superclass methods.
  42. """
  43. def contribute_to_class(self, cls, name, **kwargs):
  44. if func:
  45. func(self, cls, name, **kwargs)
  46. else:
  47. super(superclass, self).contribute_to_class(cls, name, **kwargs)
  48. setattr(cls, self.name, Creator(self))
  49. return contribute_to_class