Development of an internal social media platform with personalised dashboards for students
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.2KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. # This file was copied from django.db.models.fields.subclassing so that we could
  2. # change the Creator.__set__ behavior. Read the comment below for full details.
  3. """
  4. Convenience routines for creating non-trivial Field subclasses, as well as
  5. backwards compatibility utilities.
  6. Add SubfieldBase as the __metaclass__ for your Field subclass, implement
  7. to_python() and the other necessary methods and everything will work seamlessly.
  8. """
  9. class SubfieldBase(type):
  10. """
  11. A metaclass for custom Field subclasses. This ensures the model's attribute
  12. has the descriptor protocol attached to it.
  13. """
  14. def __new__(cls, name, bases, attrs):
  15. new_class = super(SubfieldBase, cls).__new__(cls, name, bases, attrs)
  16. new_class.contribute_to_class = make_contrib(
  17. new_class, attrs.get('contribute_to_class')
  18. )
  19. return new_class
  20. class Creator(object):
  21. """
  22. A placeholder class that provides a way to set the attribute on the model.
  23. """
  24. def __init__(self, field):
  25. self.field = field
  26. def __get__(self, obj, type=None):
  27. if obj is None:
  28. return self
  29. return obj.__dict__[self.field.name]
  30. def __set__(self, obj, value):
  31. # Usually this would call to_python, but we've changed it to pre_init
  32. # so that we can tell which state we're in. By passing an obj,
  33. # we can definitively tell if a value has already been deserialized
  34. # More: https://github.com/bradjasper/django-jsonfield/issues/33
  35. obj.__dict__[self.field.name] = self.field.pre_init(value, obj)
  36. def make_contrib(superclass, func=None):
  37. """
  38. Returns a suitable contribute_to_class() method for the Field subclass.
  39. If 'func' is passed in, it is the existing contribute_to_class() method on
  40. the subclass and it is called before anything else. It is assumed in this
  41. case that the existing contribute_to_class() calls all the necessary
  42. superclass methods.
  43. """
  44. def contribute_to_class(self, cls, name):
  45. if func:
  46. func(self, cls, name)
  47. else:
  48. super(superclass, self).contribute_to_class(cls, name)
  49. setattr(cls, self.name, Creator(self))
  50. return contribute_to_class