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.