On Mon, Feb 04, 2008 at 08:32:17AM -0500, George Vilches wrote:
>    Since we've been using a metaclass for doing a similar task, seems
>    appropriate to paste it now:
> 
>    class ModelMixinBase(ModelBase):
>        def __new__(cls, name, bases, attrs):
>            new_attrs = attrs.copy()
>            for attr,value in cls.__dict__.iteritems():
>                if isinstance(value, models.Field):
>                    new_attrs.setdefault(attr,value)
>                elif attr == 'methods':
>                    for v in value:
>                        if callable(v):
>                            new_attrs.setdefault(v.__name__, v)
>                        elif isinstance(v, str):
>                            new_attrs.setdefault(v, getattr(cls, v))
>            return super(ModelMixinBase, cls).__new__(cls, name, bases,
>    new_attrs)
>    class MixinBaseA(ModelMixinBase):
>        common_1 = models.IntegerField()
>        common_2 = models.CharField(max_length=255)
>    class ResultModel(models.Model):
>        __metaclass__ = MixinBaseA
>        specific_1 = models.IntegerField()
>    The end result should give you as far as we have been able to tell a
>    perfectly okay Django model instance (we've been using it for months
>    and haven't seen any weird behavior yet).  We know it does a touch more
>    than what yours does, but it could easily be stripped down to just be
>    the equivalent of what you've got above.

I see only one particular fault with this approach- if you ever add 
functionality to allow N inheriting parents, instead of a single line 
of inheritance.  Django internally has a rather voodoo-rific 
creation_counter in the Field class namespace, that serves as an 
instance count for each Field derivative instantiated, and it uses 
that creation_counter to determine where to insert the Field 
derivative into the Models fields list (which maps out to the sql 
column ordering).

If you ever try to extend your metaclass approach to allow mixing 
multiple parents (which makes sense, imo), the sql column ordering 
would be dependant on the order of imports.

Aside from that, nifty approach although I think I'd try to mangle the 
ModelMixinBase instance so it was invokable, and then use it like so-

class ResultModel(MixinBaseA(), MixinBaseB()):
   specific_1 = models.IntegerField()

The reason I'd try that direction is due to the creation_counter 
voodoo- if you could slightly bastardize ModelMixinBase.__call__ so 
that it was able return clones of the fields (with the 
creation_counter incremented), it would solve the sql field order 
issue I mentioned above while enabling N parent inheritance.

Just a thought.
~brian

Attachment: pgpMlTjNEbvE4.pgp
Description: PGP signature

Reply via email to