Ticket #21217: 0001-Fixed-21217-Avoid-connecting-pre-post-_init-signals-.patch

File 0001-Fixed-21217-Avoid-connecting-pre-post-_init-signals-.patch, 12.0 KB (added by Simon Charette, 11 years ago)
  • django/contrib/contenttypes/generic.py

    From 640ef30381e7c5a2ef0d92b6810f2a401ac64d5e Mon Sep 17 00:00:00 2001
    From: Simon Charette <charette.s@gmail.com>
    Date: Thu, 3 Oct 2013 13:44:10 -0400
    Subject: [PATCH] Fixed #21217 -- Avoid connecting `(pre|post)_init` signals to
     abstract senders.
    
    ---
     django/contrib/contenttypes/generic.py |  8 +++---
     django/db/models/fields/files.py       |  4 ++-
     tests/generic_relations/models.py      | 30 ++++++++++++++++-----
     tests/model_fields/models.py           | 49 ++++++++++++++++++++++++++--------
     tests/model_fields/test_imagefield.py  |  6 ++---
     5 files changed, 71 insertions(+), 26 deletions(-)
    
    diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
    index b34847b..1fdb1f1 100644
    a b from django.db.models.fields.related import ForeignObject, ForeignObjectRel  
    1414from django.db.models.related import PathInfo
    1515from django.db.models.sql.where import Constraint
    1616from django.forms import ModelForm, ALL_FIELDS
    17 from django.forms.models import (BaseModelFormSet, modelformset_factory, save_instance,
     17from django.forms.models import (BaseModelFormSet, modelformset_factory,
    1818    modelform_defines_fields)
    1919from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
    2020from django.contrib.contenttypes.models import ContentType
    class GenericForeignKey(six.with_metaclass(RenameGenericForeignKeyMethods)):  
    4646        self.cache_attr = "_%s_cache" % name
    4747        cls._meta.add_virtual_field(self)
    4848
    49         # For some reason I don't totally understand, using weakrefs here doesn't work.
    50         signals.pre_init.connect(self.instance_pre_init, sender=cls, weak=False)
     49        # Only run pre-initialization field assignment on non-abstract models
     50        if not cls._meta.abstract:
     51            signals.pre_init.connect(self.instance_pre_init, sender=cls)
    5152
    52         # Connect myself as the descriptor for this field
    5353        setattr(cls, name, self)
    5454
    5555    def instance_pre_init(self, signal, sender, args, kwargs, **_kwargs):
  • django/db/models/fields/files.py

    diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
    index 61e3eeb..557ec6e 100644
    a b class ImageField(FileField):  
    358358        # Attach update_dimension_fields so that dimension fields declared
    359359        # after their corresponding image field don't stay cleared by
    360360        # Model.__init__, see bug #11196.
    361         signals.post_init.connect(self.update_dimension_fields, sender=cls)
     361        # Only run post-initialization dimension update on non-abstract models
     362        if not cls._meta.abstract:
     363            signals.post_init.connect(self.update_dimension_fields, sender=cls)
    362364
    363365    def update_dimension_fields(self, instance, force=False, *args, **kwargs):
    364366        """
  • tests/generic_relations/models.py

    diff --git a/tests/generic_relations/models.py b/tests/generic_relations/models.py
    index d819a53..79eb59f 100644
    a b class TaggedItem(models.Model):  
    3232    def __str__(self):
    3333        return self.tag
    3434
     35
    3536class ValuableTaggedItem(TaggedItem):
    3637    value = models.PositiveIntegerField()
    3738
    38 @python_2_unicode_compatible
    39 class Comparison(models.Model):
    40     """
    41     A model that tests having multiple GenericForeignKeys
    42     """
     39
     40class AbstractComparison(models.Model):
    4341    comparative = models.CharField(max_length=50)
    4442
    4543    content_type1 = models.ForeignKey(ContentType, related_name="comparative1_set")
    4644    object_id1 = models.PositiveIntegerField()
    4745
    48     content_type2 = models.ForeignKey(ContentType,  related_name="comparative2_set")
     46    first_obj = generic.GenericForeignKey(ct_field="content_type1", fk_field="object_id1")
     47
     48
     49@python_2_unicode_compatible
     50class Comparison(AbstractComparison):
     51    """
     52    A model that tests having multiple GenericForeignKeys. One is defined
     53    through an inherited abstract model and one defined directly on this class.
     54    """
     55    content_type2 = models.ForeignKey(ContentType, related_name="comparative2_set")
    4956    object_id2 = models.PositiveIntegerField()
    5057
    51     first_obj = generic.GenericForeignKey(ct_field="content_type1", fk_field="object_id1")
    5258    other_obj = generic.GenericForeignKey(ct_field="content_type2", fk_field="object_id2")
    5359
    5460    def __str__(self):
    5561        return "%s is %s than %s" % (self.first_obj, self.comparative, self.other_obj)
    5662
     63
    5764@python_2_unicode_compatible
    5865class Animal(models.Model):
    5966    common_name = models.CharField(max_length=150)
    class Animal(models.Model):  
    6774    def __str__(self):
    6875        return self.common_name
    6976
     77
    7078@python_2_unicode_compatible
    7179class Vegetable(models.Model):
    7280    name = models.CharField(max_length=150)
    class Vegetable(models.Model):  
    7785    def __str__(self):
    7886        return self.name
    7987
     88
    8089@python_2_unicode_compatible
    8190class Mineral(models.Model):
    8291    name = models.CharField(max_length=150)
    class Mineral(models.Model):  
    8796    def __str__(self):
    8897        return self.name
    8998
     99
    90100class GeckoManager(models.Manager):
    91101    def get_queryset(self):
    92102        return super(GeckoManager, self).get_queryset().filter(has_tail=True)
    93103
     104
    94105class Gecko(models.Model):
    95106    has_tail = models.BooleanField(default=False)
    96107    objects = GeckoManager()
    97108
     109
    98110# To test fix for #11263
    99111class Rock(Mineral):
    100112    tags = generic.GenericRelation(TaggedItem)
    101113
     114
    102115class ManualPK(models.Model):
    103116    id = models.IntegerField(primary_key=True)
    104117    tags = generic.GenericRelation(TaggedItem)
    class ForProxyModelModel(models.Model):  
    110123    obj = generic.GenericForeignKey(for_concrete_model=False)
    111124    title = models.CharField(max_length=255, null=True)
    112125
     126
    113127class ForConcreteModelModel(models.Model):
    114128    content_type = models.ForeignKey(ContentType)
    115129    object_id = models.PositiveIntegerField()
    116130    obj = generic.GenericForeignKey()
    117131
     132
    118133class ConcreteRelatedModel(models.Model):
    119134    bases = generic.GenericRelation(ForProxyModelModel, for_concrete_model=False)
    120135
     136
    121137class ProxyRelatedModel(ConcreteRelatedModel):
    122138    class Meta:
    123139        proxy = True
  • tests/model_fields/models.py

    diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py
    index a85dfc4..89ea77b 100644
    a b class Foo(models.Model):  
    1818    a = models.CharField(max_length=10)
    1919    d = models.DecimalField(max_digits=5, decimal_places=3)
    2020
     21
    2122def get_foo():
    2223    return Foo.objects.get(id=1)
    2324
     25
    2426class Bar(models.Model):
    2527    b = models.CharField(max_length=10)
    2628    a = models.ForeignKey(Foo, default=get_foo)
    2729
     30
    2831class Whiz(models.Model):
    2932    CHOICES = (
    3033        ('Group 1', (
    31                 (1,'First'),
    32                 (2,'Second'),
     34                (1, 'First'),
     35                (2, 'Second'),
    3336            )
    3437        ),
    3538        ('Group 2', (
    36                 (3,'Third'),
    37                 (4,'Fourth'),
     39                (3, 'Third'),
     40                (4, 'Fourth'),
    3841            )
    3942        ),
    40         (0,'Other'),
     43        (0, 'Other'),
    4144    )
    4245    c = models.IntegerField(choices=CHOICES, null=True)
    4346
     47
    4448class BigD(models.Model):
    4549    d = models.DecimalField(max_digits=38, decimal_places=30)
    4650
     51
    4752class BigS(models.Model):
    4853    s = models.SlugField(max_length=255)
    4954
     55
    5056class BigInt(models.Model):
    5157    value = models.BigIntegerField()
    52     null_value = models.BigIntegerField(null = True, blank = True)
     58    null_value = models.BigIntegerField(null=True, blank=True)
     59
    5360
    5461class Post(models.Model):
    5562    title = models.CharField(max_length=100)
    5663    body = models.TextField()
    5764
     65
    5866class NullBooleanModel(models.Model):
    5967    nbfield = models.NullBooleanField()
    6068
     69
    6170class BooleanModel(models.Model):
    6271    bfield = models.BooleanField(default=None)
    6372    string = models.CharField(max_length=10, default='abc')
    6473
     74
    6575class FksToBooleans(models.Model):
    6676    """Model wih FKs to models with {Null,}BooleanField's, #15040"""
    6777    bf = models.ForeignKey(BooleanModel)
    6878    nbf = models.ForeignKey(NullBooleanModel)
    6979
     80
    7081class RenamedField(models.Model):
    71     modelname = models.IntegerField(name="fieldname", choices=((1,'One'),))
     82    modelname = models.IntegerField(name="fieldname", choices=((1, 'One'),))
     83
    7284
    7385class VerboseNameField(models.Model):
    7486    id = models.AutoField("verbose pk", primary_key=True)
    class VerboseNameField(models.Model):  
    99111    field21 = models.TimeField("verbose field21")
    100112    field22 = models.URLField("verbose field22")
    101113
     114
    102115# This model isn't used in any test, just here to ensure it validates successfully.
    103116# See ticket #16570.
    104117class DecimalLessThanOne(models.Model):
    105118    d = models.DecimalField(max_digits=3, decimal_places=3)
    106119
     120
    107121class DataModel(models.Model):
    108122    short_data = models.BinaryField(max_length=10, default=b'\x08')
    109123    data = models.BinaryField()
    class DataModel(models.Model):  
    111125###############################################################################
    112126# FileField
    113127
     128
    114129class Document(models.Model):
    115130    myfile = models.FileField(upload_to='unused')
    116131
    if Image:  
    126141        """
    127142        def __init__(self, *args, **kwargs):
    128143            self.was_opened = False
    129             super(TestImageFieldFile, self).__init__(*args,**kwargs)
     144            super(TestImageFieldFile, self).__init__(*args, **kwargs)
     145
    130146        def open(self):
    131147            self.was_opened = True
    132148            super(TestImageFieldFile, self).open()
    if Image:  
    146162        name = models.CharField(max_length=50)
    147163        mugshot = TestImageField(storage=temp_storage, upload_to='tests')
    148164
    149     class PersonWithHeight(models.Model):
     165    class AbsctractPersonWithHeight(models.Model):
    150166        """
    151         Model that defines an ImageField with only one dimension field.
     167        Abstract model that defines an ImageField with only one dimension field
     168        to make sure the dimension update is correctly run on concrete subclass
     169        instance post-initialization.
    152170        """
    153         name = models.CharField(max_length=50)
    154171        mugshot = TestImageField(storage=temp_storage, upload_to='tests',
    155172                                 height_field='mugshot_height')
    156173        mugshot_height = models.PositiveSmallIntegerField()
    157174
     175        class Meta:
     176            abstract = True
     177
     178    class PersonWithHeight(AbsctractPersonWithHeight):
     179        """
     180        Concrete model that subclass an abctract one with only on dimension
     181        field.
     182        """
     183        name = models.CharField(max_length=50)
     184
    158185    class PersonWithHeightAndWidth(models.Model):
    159186        """
    160187        Model that defines height and width fields after the ImageField.
  • tests/model_fields/test_imagefield.py

    diff --git a/tests/model_fields/test_imagefield.py b/tests/model_fields/test_imagefield.py
    index ce7d33e..ec41247 100644
    a b class ImageFieldTests(ImageFieldTestMixin, TestCase):  
    134134        p = self.PersonModel.objects.get(name="Joan")
    135135        path = p.mugshot.path
    136136        shutil.move(path, path + '.moved')
    137         p2 = self.PersonModel.objects.get(name="Joan")
     137        self.PersonModel.objects.get(name="Joan")
    138138
    139139    def test_delete_when_missing(self):
    140140        """
    class TwoImageFieldTests(ImageFieldTestMixin, TestCase):  
    412412        # was opened.
    413413        self.assertEqual(p.mugshot.was_opened, False)
    414414        self.assertEqual(p.headshot.was_opened, False)
    415         self.check_dimensions(p, 4, 8,'mugshot')
     415        self.check_dimensions(p, 4, 8, 'mugshot')
    416416        self.check_dimensions(p, 8, 4, 'headshot')
    417417        # After checking dimensions on the image fields, the files will
    418418        # have been opened.
    class TwoImageFieldTests(ImageFieldTestMixin, TestCase):  
    422422        # check dimensions again, the file should not have opened.
    423423        p.mugshot.was_opened = False
    424424        p.headshot.was_opened = False
    425         self.check_dimensions(p, 4, 8,'mugshot')
     425        self.check_dimensions(p, 4, 8, 'mugshot')
    426426        self.check_dimensions(p, 8, 4, 'headshot')
    427427        self.assertEqual(p.mugshot.was_opened, False)
    428428        self.assertEqual(p.headshot.was_opened, False)
Back to Top