Ticket #3148: revised.add.getter.setter.patch

File revised.add.getter.setter.patch, 6.2 KB (added by jerf@…, 13 years ago)

add documentation, fix minor whitespace issue, supercede previous patch

  • django/db/models/base.py

     
    9090
    9191    def __init__(self, *args, **kwargs):
    9292        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
     93        self._django_initializing = True
    9394        for f in self._meta.fields:
    9495            if isinstance(f.rel, ManyToOneRel):
    9596                try:
     
    127128            setattr(self, self._meta.fields[i].attname, arg)
    128129        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
    129130
     131        del self._django_initializing
     132
    130133    def add_to_class(cls, name, value):
    131134        if name == 'Admin':
    132135            assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value))
  • django/db/models/fields/__init__.py

     
    7070        core=False, rel=None, default=NOT_PROVIDED, editable=True,
    7171        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
    7272        unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
    73         help_text='', db_column=None):
     73        help_text='', db_column=None, getter=None, setter=None):
    7474        self.name = name
    7575        self.verbose_name = verbose_name
    7676        self.primary_key = primary_key
     
    8686        self.radio_admin = radio_admin
    8787        self.help_text = help_text
    8888        self.db_column = db_column
     89        self.getter = getter
     90        self.setter = setter
    8991
    9092        # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
    9193        self.db_index = db_index
     
    139141        cls._meta.add_field(self)
    140142        if self.choices:
    141143            setattr(cls, 'get_%s_display' % self.name, curry(cls._get_FIELD_display, field=self))
     144        if self.setter is not None or self.getter is not None:
     145            self.create_property_on_class(cls)
    142146
     147    def create_property_on_class(self, cls):
     148        """create the property to support setters and getters"""
     149        name = self.name
     150        field_att = "_%s" % name
     151
     152        if self.getter:
     153            getter_name = self.getter
     154            def get_func(self):
     155                value = getattr(self, field_att)
     156                return getattr(self, getter_name)(value)
     157        else:
     158            def get_func(self):
     159                return getattr(self, field_att)
     160
     161        if self.setter:
     162            setter_name = self.setter
     163            def set_func(self, value):
     164                if hasattr(self, '_django_initializing'):
     165                    setattr(self, field_att, value)
     166                else:
     167                    setattr(self, field_att,
     168                            getattr(self, setter_name)(value))
     169        else:
     170            def set_func(self, value):
     171                setattr(self, field_att, value)
     172
     173        setattr(cls, name, property(get_func, set_func))
     174
    143175    def get_attname(self):
    144176        return self.name
    145177
  • tests/modeltests/getters_setters/models.py

     
     1"""
     2Test the 'getter' and 'setter' functionality on fields.
     3
     4This tests a field with a setter, a field with a getter, and a field
     5with both. Since the getter/setter implementation is at the Field
     6level, and I've verified that all Field objects pass through the code
     7that constructs these properties, I believe it would be redundent to
     8test all the Field Types individually.
     9
     10Doc note: Setters
     11"""
     12
     13from django.db import models
     14
     15class GetSet(models.Model):
     16    has_getter = models.CharField(maxlength=20, getter='simple_getter')
     17    has_setter = models.CharField(maxlength=20, setter='simple_setter')
     18    has_both = models.CharField(maxlength=20, getter='simple_getter',
     19                                setter='updater')
     20    updated_length_field = models.IntegerField(default=0)
     21
     22    def simple_getter(self, value):
     23        return value + "_getter"
     24    def simple_setter(self, value):
     25        return value + "_setter"
     26    def updater(self, value):
     27        self.updated_length_field = len(value)
     28        return value
     29
     30
     31__test__ = {'API_TESTS':"""
     32>>> a = GetSet(has_getter='x', has_setter='y', has_both='z')
     33>>> a.has_getter
     34'x_getter'
     35>>> a.has_setter
     36'y'
     37>>> a.has_both
     38'z_getter'
     39
     40# Setter has not run yet
     41
     42>>> a.updated_length_field
     430
     44>>> a.has_both = 'abcd'
     45>>> a.updated_length_field
     464
     47>>> a.save()
     48>>> a_id = a.id
     49>>> del a
     50>>> a = GetSet.objects.get(id=a_id)
     51>>> a.updated_length_field
     524
     53"""}
     54                                 
     55     
  • docs/model-api.txt

     
    548548processing using the object's ``AddManipulator`` or ``ChangeManipulator``
    549549classes. Default is ``True``.
    550550
     551``getter``
     552~~~~~~~~~~
     553
     554A string indicating a method of the class to call when you try
     555to retrieve the value of the field. The method will be passed as its
     556only argument the current "underlying value" of the field (as received
     557from the database, object construction, or previous setting
     558operation), and the return value of that method is what the user
     559receives.
     560
    551561``help_text``
    552562~~~~~~~~~~~~~
    553563
     
    581591Don't use this for a field unless it's a ``ForeignKey`` or has ``choices``
    582592set.
    583593
     594``setter``
     595~~~~~~~~~~
     596
     597A string indicating a method of the class to call when you try to set
     598the value of the field. The method will be passed as its only argument
     599the value the user is setting the field to, and the return value is
     600what will actually be set in the database.
     601
     602The setter will not be run when the object is created,  either by
     603database retrieval or construction.
     604
    584605``unique``
    585606~~~~~~~~~~
    586607
Back to Top