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

File revised2.add.getter.setter.patch, 7.0 KB (added by jerf@…, 17 years ago)

figured out what the numbers in the test cases meant; documentation example added for getter/setter

  • 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"""
     235. Getters and setters
     3
     4Each field can have a 'getter' and a 'setter'.
     5
     6The getter can modify the values received from the database. A
     7method is specified as a string that names it. When the user of
     8your model requests that field, the 'getter' will be called with the
     9current database value of the field, and what is returned by the
     10method is what the user will receive as the value of the field.
     11
     12The setter can modify the value of the field before it is sent to the
     13database. A method is specified as a string that names it. When the
     14user of your model sets that field, the 'setter' will be called with
     15the value the user is setting, and what is returned by the setter is
     16what will be saved in the database.
     17
     18If you return the same value that came in, you can use a 'setter' as a
     19hook to update other pieces of data when the value of the field
     20changes.
     21
     22Setters do not run during construction.
     23"""
     24
     25from django.db import models
     26
     27class GetSet(models.Model):
     28    has_getter = models.CharField(maxlength=20, getter='simple_getter')
     29    has_setter = models.CharField(maxlength=20, setter='simple_setter')
     30    has_both = models.CharField(maxlength=20, getter='simple_getter',
     31                                setter='updater')
     32    updated_length_field = models.IntegerField(default=0)
     33
     34    def simple_getter(self, value):
     35        return value + "_getter"
     36    def simple_setter(self, value):
     37        return value + "_setter"
     38    def updater(self, value):
     39        self.updated_length_field = len(value)
     40        return value
     41
     42
     43__test__ = {'API_TESTS':"""
     44>>> a = GetSet(has_getter='x', has_setter='y', has_both='z')
     45
     46# The getter filters the 'x'
     47>>> a.has_getter
     48'x_getter'
     49
     50# The setter does not run during construction.
     51>>> a.has_setter
     52'y'
     53>>> a.has_both
     54'z_getter'
     55
     56# Setter has not run yet, so the updated_length_field has not been set
     57>>> a.updated_length_field
     580
     59>>> a.has_both = 'abcd'
     60
     61# Now the setter has been called.
     62>>> a.updated_length_field
     634
     64>>> a.save()
     65>>> a_id = a.id
     66>>> del a
     67
     68# And we can see the new updated_length_field was indeed saved in the
     69# database.
     70>>> a = GetSet.objects.get(id=a_id)
     71>>> a.updated_length_field
     724
     73"""}
     74                                 
     75     
  • 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