Ticket #3148: 3148-propertyfield.diff

File 3148-propertyfield.diff, 4.9 KB (added by berdario, 8 years ago)

This approach works with m2m fields and inherited fields

  • django/db/models/fields/__init__.py

    === modified file 'django/db/models/fields/__init__.py'
    old new  
    11831183        }
    11841184        defaults.update(kwargs)
    11851185        return super(URLField, self).formfield(**defaults)
     1186
     1187def property_field(field):
     1188    class PropertyField(property):
     1189        """property subclass to be used to "wrap" another Field, not a true Field per-se"""
     1190       
     1191        def __init__(self, fget=None, fset=None, fdel=None, doc=None):
     1192            super(PropertyField, self).__init__(fget, fset, fdel, doc)
     1193            self.field = field
     1194            self.creation_counter = Field.creation_counter
     1195            Field.creation_counter += 1
     1196           
     1197        def __getattr__(self, name):
     1198            return getattr(self.field, name)
     1199           
     1200        def contribute_to_class(self, cls, name):
     1201            self.name, self.attname, self.column = (name,)*3
     1202            self.verbose_name = name.replace('_', ' ')
     1203            from django.db.models.fields.related import ManyToManyRel
     1204            if not field.rel or not isinstance(field.rel, ManyToManyRel):
     1205                cls._meta.add_field(self)
     1206            setattr(cls, name, self)
     1207   
     1208    return PropertyField
     1209
     1210   
     1211 No newline at end of file
  • tests/regressiontests/model_fields/models.py

    === modified file 'tests/regressiontests/model_fields/models.py'
    old new  
    1515
    1616from django.core.files.storage import FileSystemStorage
    1717from django.db import models
     18from django.db.models.fields import property_field
    1819from django.db.models.fields.files import ImageFieldFile, ImageField
    1920
    2021
     
    6667    bfield = models.BooleanField()
    6768    string = models.CharField(max_length=10, default='abc')
    6869
     70class FooGetSet(models.Model):
     71    _s = models.SlugField(max_length=255)
     72    _c = models.CharField(max_length=255)
     73
     74    @property_field(_s)
     75    def s(self):
     76        return self._s
     77    @s.setter
     78    def s(self, value):
     79        if value is "not_acceptable":
     80            raise ValueError("not acceptable")
     81        self._s = value
     82
     83
     84class GetSetSubclass(FooGetSet):
     85    @property_field(filter(lambda x: x.name == "_c", FooGetSet._meta.fields)[0])
     86    def c(self):
     87        return self._c[:-15]
     88   
     89    @c.setter
     90    def c(self, value):
     91        self._c = value + " useless foobar"
     92       
     93class GetSetRel(models.Model):
     94    _foos = models.ManyToManyField(FooGetSet)
     95   
     96    @property_field(_foos)
     97    def foos(self):
     98        return self._foos
     99   
     100    @foos.setter
     101    def foos(self, values):
     102        self._foos = [FooGetSet.objects.get_or_create(s=val)[0] for val in values]
     103
    69104###############################################################################
    70105# FileField
    71106
  • tests/regressiontests/model_fields/tests.py

    === modified file 'tests/regressiontests/model_fields/tests.py'
    old new  
    88from django.db.models.fields.files import FieldFile
    99from django.utils import unittest
    1010
    11 from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document
     11from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document, FooGetSet, GetSetSubclass, GetSetRel
    1212
    1313# If PIL available, do these tests.
    1414if Image:
     
    317317    def test_lookup_integer_in_textfield(self):
    318318        self.assertEqual(Post.objects.filter(body=24).count(), 0)
    319319
     320class FieldProperties(test.TestCase):
     321    def test_get_set(self):
     322        """
     323        Test basic property functionality of a SlugField
     324        """
     325        f = FooGetSet(s="test")
     326        self.assertEqual(f.s, "test")
     327        f.s = "test2"
     328        self.assertEqual(f.s, "test2")
     329
     330        def set_non_acceptable():
     331            f.s = "not_acceptable"
     332        self.assertRaises(ValueError, set_non_acceptable)
     333        self.assertEqual(f.s, "test2")
     334
     335        f.save()
     336        f = FooGetSet.objects.get(pk=f.pk)
     337        self.assertEqual(f.s, "test2")
     338   
     339    def test_inheritance(self):
     340        """
     341        Test a property that's working on an inherited field
     342        """
     343        sub = GetSetSubclass(s="foo", c="bar")
     344       
     345        self.assertEqual(sub._c, "bar useless foobar")
     346        self.assertEqual(sub.c, "bar")
     347   
     348    def test_m2m(self):
     349        """
     350        Test a property that's working on a many to many relationship
     351        """
     352        r = GetSetRel()
     353        r.save()
     354       
     355        r.foos = ["a", "b", "c", "d"]
     356        self.assertEqual(len(r.foos.all()), 4)
     357       
     358        self.assertTrue(r in FooGetSet.objects.get(s="a").getsetrel_set.all())
     359
    320360class FileFieldTests(unittest.TestCase):
    321361    def test_clearable(self):
    322362        """
Back to Top