Opened 8 years ago

Closed 8 years ago

#26799 closed New feature (duplicate)

Model related signals' receiver could not receive its proxy models

Reported by: Yang Wang Owned by: nobody
Component: Database layer (models, ORM) Version: 1.9
Severity: Normal Keywords: Model, Signal, Generation
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

We have to connect the same receiver to its all proxy models one by one

class TestModel(models.Model):
    field1 = models.CharField(max_length=64)
    field2 = models.CharField(max_length=64)

    class Meta:
        db_table = 'app_label_test_model'

class ProxyTestModel(TestModel):
    class Meta:
        proxy = True

from django.db.models.signals import pre_save
def on_test_model_change(sender, instance, **kwargs):
    if not instance.field1.startswith('*'):
        instance.field1 = u'*' + instance.field1
pre_save.connect(on_test_model_change, sender=TestModel)
# pre_save.connect(on_test_model_change, sender=ProxyTestModel)

>>> t = TestModel()
>>> t.save()
>>> t.field1
u'*'
>>> pt = ProxyTestModel()
>>> pt.save()
>>> pt.field1
u''

Otherwise, we should consider to split one Model to manage it more conveniently and safely.
As there is an attribute 'concrete_model' kept in Model's Option, could we take the benefits of it?

class RealTestModel1(models.Model):
    field1 = models.CharField(max_length=64)
    class Meta:
        managed = False
        db_table = 'app_label_test_model'

class RealTestModel2(models.Model):
    field2 = models.CharField(max_length=64)
    class Meta:
        managed = False
        db_table = 'app_label_test_model'

In my project, i hacked like this for more admin site features which could be implemented in Model's generation process:

from django.db.models.base import ModelBase
from django.dispatch import dispatcher
# for adapting to sub-models
_make_id = dispatcher._make_id
def _new_make_id(target):
    if isinstance(target, ModelBase):
        return id(getattr(target, '_concrete_model', target._meta.concrete_model))
    return _make_id(target)

dispatcher._make_id = _new_make_id

# ...

class ABSModelBase(ModelBase):
    '''
    Abstract Meta-Class to make new model performs as concrete model
    '''

    _concrete_model = ModelBase

    def __subclasscheck__(cls, subclass):
        return issubclass(subclass, cls._concrete_model)

    def __instancecheck__(cls, instance):
        return isinstance(instance, cls._concrete_model)

# ...
    # create new class
    new_class = ABSModelBase.__new__(
        ABSModelBase, name, tuple(bases), attrs,
        )

    # register new_class as subclass of concrete_model
    new_class.__bases__ = (concrete_meta.model, ) + new_class.__bases__
    # register subclass and instance checking
    new_class._concrete_model = concrete_meta.model

Change History (1)

comment:1 by Tim Graham, 8 years ago

Resolution: duplicate
Status: newclosed

Looks like a duplicate of #9318.

Note: See TracTickets for help on using tickets.
Back to Top