Rafe, do you think we'll be seeing a db.ModelMixin anytime in the near
future?


On 11 March 2010 10:01, Rafe <slobberch...@gmail.com> wrote:

>  The built-in property classes are not likely to change in future
> releases.  I've already written an article about extending properties
> and am loath to break peoples existing applications (even though it
> sometimes happens by mistake - and we then revert those changes):
>
>  http://code.google.com/appengine/articles/extending_models.html
>
>  Nice analysis PK.
>
>  As described, the main problem with your first approach was that
> properties are not initialized unless they use the Propertied base
> class.  The problem with the Propertied base class is that it is too
> tied to the actual Datastore implementation.  Ideally, there would be
> a less specific meta-class that simply does property initialization
> which can be used by other class that do not inherit from models but
> want to be mixins.  This would be ideal:
>
>  class CoolFeature(db.ModelMixin):
>    my_prop = db.StringProperty()
>
>  class IUseCoolFeature(CoolFeature, db.Model):  ...
>
>  Or what if you wanted to use it with an Expando?
>
>  class IUseCoolFeature(CoolFeature, db.Expando): ...
>
>  Learned quite a bit since releasing db.py.  Expando should have been
> written as a mixin in the first place.
>
> On Mar 5, 1:31 am, Nickolas Daskalou <n...@daskalou.com> wrote:
> > c...@your solution, PK!
> >
> > Since db.PropertiedClass is not documented in the official docs, I'm
> > assuming there's a chance that its implemented could change in future
> > releases, and possibly break your code yeah?
> >
> > Can someone from Google please comment on whether db.PropertiedClass is
> > "concrete" enough to be able to use it in such a manner as described in
> PK's
> > article?
> >
> > Nick
> >
> > On 5 March 2010 20:18, Nickolas Daskalou <n...@daskalou.com> wrote:
> >
> >
> >
> > > Thanks PK, I'll check it out now.
> >
> > > Nick
> >
> > > On 5 March 2010 19:41, PK <p...@gae123.com> wrote:
> >
> > >> Hi Nick,
> >
> > >> I have been using the pattern described by Rafe very successfully in
> > >> my app. Regarding the problem you are desribing I have written up how
> > >> I solved the problem here:
> >
> > >>http://www.gae123.com/articles/tds/model-mixin.html
> >
> > >> Read the whole page for the details or just scroll to the bottom for
> > >> the solution that has worked for me.
> >
> > >> PK
> > >>http://www.gae123.com
> >
> > >> On Mar 4, 10:22 pm, Nickolas Daskalou <n...@daskalou.com> wrote:
> > >> > Using non-Model mix-ins worked a treat. Thanks again Rafe.
> >
> > >> > There is one small problem I'm hoping you can help me with (again).
> It's
> > >> not
> > >> > a show-stopper because I can work around it, however I'm hoping
> you'd
> > >> know
> > >> > of a nicer way to do this. Note that it's not only specific to
> > >> PolyModel,
> > >> > but to db.Model as well.
> >
> > >> > The problem is with adding extra db.* properties to these mix-ins
> (so
> > >> that
> > >> > all subclasses that use the mix-in get these extra properties stored
> in
> > >> the
> > >> > Datastore).
> >
> > >> > Let's say I change the CoolFeature mix-in to this:
> >
> > >> > class CoolFeature(object):
> >
> > >> > *  cool_name = db.StringProperty()*
> >
> > >> >   def put(self):
> > >> >     self.cool_name = 'Cool ' + self.name
> > >> >     super(CoolFeature, self).put()
> >
> > >> > class MyModel(CoolFeature,db.Model):
> >
> > >> >   name = db.StringProperty()
> >
> > >> > If I then create an instance of MyModel and try put()'ing it to the
> > >> > Datastore:
> >
> > >> > mm = MyModel(name='blah')
> > >> > mm.put()
> >
> > >> > I get this error:
> >
> > >> > Traceback (most recent call last):
> > >> >   ...
> > >> >   File
> >
> > >>
> "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngi
> ­ne-default.bundle/Contents/Resources/google_appengine/google/appengine/ext
> /­db/__init__.py",
> > >> > line 473, in __set__
> > >> >     setattr(model_instance, self._attr_name(), value)
> > >> >   File
> >
> > >>
> "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngi
> ­ne-default.bundle/Contents/Resources/google_appengine/google/appengine/ext
> /­db/__init__.py",
> > >> > line 588, in _attr_name
> > >> >     return '_' + self.name
> > >> > TypeError: cannot concatenate 'str' and 'NoneType' objects
> >
> > >> > This error occurs both on the dev and production servers.
> >
> > >> > Upon further investigation, the error occurs because the name
> property
> > >> of
> > >> > the underlying Property superclass of the cool_name property
> instance is
> > >> > None. So I then changed the bold line above to:
> >
> > >> >   cool_name = db.StringProperty(name='cool_name')
> >
> > >> > This got rid of the error being raised, however the cool_name
> property
> > >> was
> > >> > not saved to the Datastore (only the name property was).
> >
> > >> > The workaround is to add the property cool_name to each
> > >> > CoolFeaturesubclass. So it's not terribly bad, but if you know of a
> > >> > better way to
> > >> > accomplish what I'm trying to do, I'd love to hear it.
> >
> > >> > Cheers,
> >
> > >> > Nick
> >
> > >> > On 5 March 2010 12:40, Nickolas Daskalou <n...@daskalou.com> wrote:
> >
> > >> > > Thanks for your reply Rafe. Using non-Model mix-ins seems like the
> way
> > >> to
> > >> > > go.
> >
> > >> > > As with many App Engine developers, my Python experience is
> equivalent
> > >> to
> > >> > > my App Engine experience, so I appreciated the Python lesson ;)
> >
> > >> > > Nick
> >
> > >> > > On 5 March 2010 08:52, Rafe <slobberch...@gmail.com> wrote:
> >
> > >> > >>  There is currently no proper way to do "re-root" a polymodel the
> way
> > >> > >> you are describing.  However, there may be a solution for your
> > >> > >> particular problem.  I don't know enough about your actual
> > >> > >> implementation however you might get away with simply doing a
> non-
> > >> > >> Model based mix-in.  So, write your memcache utility class AS IF
> it
> > >> > >> inherits from PolyModel, but don't actually allow it to do so.
>  Like
> > >> > >> this:
> >
> > >> > >>    class CoolFeature(object):
> >
> > >> > >>      def put(self):
> > >> > >>        ... clear memcache ...
> > >> > >>        super(CoolFeature, self).put()
> >
> > >> > >>  Now define your root class:
> >
> > >> > >>    class MyModel(CoolFeature, polymodel.PolyModel):
> > >> > >>      ...
> >
> > >> > >>  Here comes the Python lesson, so forgive me if you already know
> all
> > >> > >> this ;)
> >
> > >> > >>  The key is that you use 'super' correctly and that you have
> > >> > >> CoolFeature be the first class your model class inherits from.
> > >> > >> 'super' allows you to traverse your objects functionality
> correctly
> > >> > >> according to the python "method resolution order".  You can see
> this
> > >> > >> order by for any class by studying MyModel.__mro__.  This
> indicates
> > >> > >> the order which calls to super will traverse your class
> definitions.
> > >> > >> If you do:
> >
> > >> > >> class A(object):
> >
> > >> > >>  def p(self):
> > >> > >>    print 'A'
> >
> > >> > >> class B(object):
> >
> > >> > >>  def p(self):
> > >> > >>    print 'B'
> > >> > >>    super(B, self).p()
> >
> > >> > >> class C(B, A):
> >
> > >> > >>  def p(self):
> > >> > >>    print 'C'
> > >> > >>    super(C, self).p()
> >
> > >> > >> ...calling C().p() will print:
> >
> > >> > >>  C
> > >> > >>  B
> > >> > >>  A
> >
> > >> > >>  You should be able to implement whatever functionality you need
> this
> > >> > >> way.  Let me know if there are issues with doing that.
> >
> > >> > >> On Mar 3, 7:40 pm, Nickolas Daskalou <n...@daskalou.com> wrote:
> > >> > >> > I should state that I can set the entity kind that's saved in
> the
> > >> > >> > Datastore by adding a kind() method on my "real" models,
> however
> > >> the
> > >> > >> > class list property of the saved entities still includes the
> > >> "special"
> > >> > >> > PolyModel subclass in it, and I'm not sure if that's a bad
> thing or
> > >> > >> > not.
> >
> > >> > >> > On Mar 4, 2:16 pm, Nickolas Daskalou <n...@daskalou.com>
> wrote:
> >
> > >> > >> > > I've been trying to create a "special" subclass of PolyModel
> > >> (that
> > >> > >> does cool
> > >> > >> > > stuff like update Memcache after an entity put()) which my
> > >> polymodel
> > >> > >> models
> > >> > >> > > can inherit from (instead of inheriting from
> > >> db.polymodel.PolyModel).
> >
> > >> > >> > > This has the nasty side effect though of making that
>  "special"
> > >> > >> subclass of
> > >> > >> > > PolyModel the root class for my polymodel models.
> >
> > >> > >> > > Is there a way around this?
> >
> > >> > >> > > Eg. Telling db.polymodel.PolyModel to NOT include the first
> > >> direct
> > >> > >> subclass
> > >> > >> > > in the class hierarchy that is saved to the Datastore? Or
> writing
> > >> my
> > >> > >> own
> > >> > >> > > PolyModel by basically copying db.polymodel and changing code
> > >> where
> > >> > >> > > appropriate?
> >
> > >> > >> > > Appreciate any help.
> >
> > >> > >> > > Nick
> >
> > >> > >> --
> > >> > >> You received this message because you are subscribed to the
> Google
> > >> Groups
> > >> > >> "Google App Engine" group.
> > >> > >> To post to this group, send email to
> > >> google-appeng...@googlegroups.com.
> > >> > >> To unsubscribe from this group, send email to
> > >> > >> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com><google-appengine%2Bunsubscrib
> e...@googlegroups.com>
> > >> <google-appengine%2bunsubscrib...@googlegroups.com>
> > >> > >> .
> > >> > >> For more options, visit this group at
> > >> > >>http://groups.google.com/group/google-appengine?hl=en.-Hidequoted
> > >> text -
> >
> > >> > - Show quoted text -
> >
> > >> --
> > >> You received this message because you are subscribed to the Google
> Groups
> > >> "Google App Engine" group.
> > >> To post to this group, send email to
> google-appeng...@googlegroups.com.
> > >> To unsubscribe from this group, send email to
> > >> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com><google-appengine%2Bunsubscrib
> e...@googlegroups.com>
> > >> .
> > >> For more options, visit this group at
> > >>http://groups.google.com/group/google-appengine?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Google App Engine" group.
> To post to this group, send email to google-appeng...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-appengine?hl=en.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To post to this group, send email to google-appeng...@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.

Reply via email to