thirdparty/google_appengine/google/appengine/ext/db/polymodel.py
changeset 2864 2e0b0af889be
parent 828 f5fd65cc3bf3
equal deleted inserted replaced
2862:27971a13089f 2864:2e0b0af889be
    85 
    85 
    86       __root_class__: If the new class is a root class, __root_class__ is set to
    86       __root_class__: If the new class is a root class, __root_class__ is set to
    87         itself so that it subclasses can quickly know what the root of
    87         itself so that it subclasses can quickly know what the root of
    88         their hierarchy is and what kind they are stored in.
    88         their hierarchy is and what kind they are stored in.
    89       __class_hierarchy__: List of classes describing the new model's place
    89       __class_hierarchy__: List of classes describing the new model's place
    90         in the class hierarchy.  The first element is always the root
    90         in the class hierarchy in reverse MRO order.  The first element is
    91         element while the last element is the new class itself.  For example:
    91         always the root class while the last element is always the new class.
    92 
    92 
       
    93         MRO documentation: http://www.python.org/download/releases/2.3/mro/
       
    94 
       
    95         For example:
    93           class Foo(PolymorphicClass): ...
    96           class Foo(PolymorphicClass): ...
    94 
    97 
    95           class Bar(Foo): ...
    98           class Bar(Foo): ...
    96 
    99 
    97           class Baz(Bar): ...
   100           class Baz(Bar): ...
   105     classes, are inserted in to the class-map which maps the class-key to
   108     classes, are inserted in to the class-map which maps the class-key to
   106     implementation.  This class key is consulted using the polymorphic instances
   109     implementation.  This class key is consulted using the polymorphic instances
   107     discriminator (the 'class' property of the entity) when loading from the
   110     discriminator (the 'class' property of the entity) when loading from the
   108     datastore.
   111     datastore.
   109     """
   112     """
   110     if name == 'PolyModel' or PolyModel not in bases:
   113     if name == 'PolyModel':
   111       db._initialize_properties(cls, name, bases, dct)
   114       super(PolymorphicClass, cls).__init__(name, bases, dct, map_kind=False)
   112       super(db.PropertiedClass, cls).__init__(name, bases, dct)
   115       return
   113     else:
   116 
       
   117     elif PolyModel in bases:
       
   118       if getattr(cls, '__class_hierarchy__', None):
       
   119         raise db.ConfigurationError(('%s cannot derive from PolyModel as '
       
   120             '__class_hierarchy__ is already defined.') % cls.__name__)
       
   121       cls.__class_hierarchy__ = [cls]
   114       cls.__root_class__ = cls
   122       cls.__root_class__ = cls
   115       super(PolymorphicClass, cls).__init__(name, bases, dct)
   123       super(PolymorphicClass, cls).__init__(name, bases, dct)
   116 
   124     else:
   117     if name == 'PolyModel':
   125       super(PolymorphicClass, cls).__init__(name, bases, dct, map_kind=False)
   118       return
   126 
   119 
   127       cls.__class_hierarchy__ = [c for c in reversed(cls.mro())
   120     if cls is not cls.__root_class__:
   128           if issubclass(c, PolyModel) and c != PolyModel]
   121       poly_class = None
   129 
   122       for base in cls.__bases__:
   130       if cls.__class_hierarchy__[0] != cls.__root_class__:
   123         if issubclass(base, PolyModel):
       
   124           poly_class = base
       
   125           break
       
   126       else:
       
   127         raise db.ConfigurationError(
   131         raise db.ConfigurationError(
   128             "Polymorphic class '%s' does not inherit from PolyModel."
   132             '%s cannot be derived from both root classes %s and %s' %
   129             % cls.__name__)
   133             (cls.__name__,
   130 
   134             cls.__class_hierarchy__[0].__name__,
   131       cls.__class_hierarchy__ = poly_class.__class_hierarchy__ + [cls]
   135             cls.__root_class__.__name__))
   132     else:
       
   133       cls.__class_hierarchy__ = [cls]
       
   134 
   136 
   135     _class_map[cls.class_key()] = cls
   137     _class_map[cls.class_key()] = cls
   136 
   138 
   137 
   139 
   138 class PolyModel(db.Model):
   140 class PolyModel(db.Model):
   308         raise db.KindError('No implementation for class \'%s\'' % key)
   310         raise db.KindError('No implementation for class \'%s\'' % key)
   309       return poly_class.from_entity(entity)
   311       return poly_class.from_entity(entity)
   310     return super(PolyModel, cls).from_entity(entity)
   312     return super(PolyModel, cls).from_entity(entity)
   311 
   313 
   312   @classmethod
   314   @classmethod
   313   def all(cls):
   315   def all(cls, **kwds):
   314     """Get all instance of a class hierarchy.
   316     """Get all instance of a class hierarchy.
       
   317 
       
   318     Args:
       
   319       kwds: Keyword parameters passed on to Model.all.
   315 
   320 
   316     Returns:
   321     Returns:
   317       Query with filter set to match this class' discriminator.
   322       Query with filter set to match this class' discriminator.
   318     """
   323     """
   319     query = super(PolyModel, cls).all()
   324     query = super(PolyModel, cls).all(**kwds)
   320     if cls != cls.__root_class__:
   325     if cls != cls.__root_class__:
   321       query.filter(_CLASS_KEY_PROPERTY + ' =', cls.class_name())
   326       query.filter(_CLASS_KEY_PROPERTY + ' =', cls.class_name())
   322     return query
   327     return query
   323 
   328 
   324   @classmethod
   329   @classmethod