Code

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

File revised2.add.getter.setter.patch, 7.0 KB (added by jerf@…, 7 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