Thanks for your advice Nick. My actual app is a bit more complex than the example I gave. I'll explain more in my response to your comments below.
Will this be an all-or-nothing proposition? Eg, if the put of 'foo' changed > the foo_name, they'll all need updating, otherwise none of them will? In > that case, you'd be better off checking if it's changed, and updating them > all (without the inequality filter) if it did change. > Yes, indeed it's all-or-nothing. The above will change every single Bar and Baz entity that doesn't match > foo's entity name, though, including those that have nothing to do with the > foo you modified. > Yep, that's true. In my real app though, I don't want to query on foo's name, but instead on foo's "metadata signature", which is a hash of a combination of foo's key and properties (or rather, the properties that reverse-referenced entities duplicate, such as foo's name). Depending on how many Bar and Baz entities there are per Foo, you could > just drop the inequality and filter them out once they're fetched. > I have ReferenceProperty properties all over the place in my model design, so there are many Foo-type Models, some with up to a dozen different reverse-referenced Bar/Baz-type Models, with each of those Foo->Bar/Baz relations potentially having thousands of entities. Given that you're already hard-coding in the list of collections, you could > avoid the need for a 'get_model_class_for_collection' method by replacing > the loop with: > > "for model_class in (Bar, Baz):" > In my real app I'm not hard-coding these (due to the maintenance required as the model design evolves), I'm trying to get them dynamically, see this other thread I created: http://groups.google.com/group/google-appengine/browse_thread/thread/1a6e911f3eff79ed However, I may indeed need to hard-code these if I can't find any satisfactory way of getting all the "collection_name"s dynamically. Now more about my real app... I have a mixin class for Models to inherit from, which looks like this: class ModelCommons(object): def get_metadata_signature(self): return hashlib.sha1('Kind:%s|ID:%s|KeyName:%s|Prop:%s' % ( self.kind(), self.key().id(), self.key().name(), repr(self.get_current_metadata()))).hexdigest() def get_current_metadata(self): meta = [] for prop_name in self.__class__.meta_property_names: meta.append((prop_name, getattr(self.__class__, prop_name).get_value_for_datastore(self))) return meta def update_collections_metadata(self): current_metadata_signature = self.get_metadata_signature() for collection_name in self.get_collection_names() # In a perfect world model_class = self.get_model_class_from_collection_name(collection_name) # The magic method I was looking for reference_prop_name = self.get_reverse_reference_property_name_from_collection_name(collection_name) # Another magic method that I need metadatasig_prop_name = '%s_metadata_signature' % reference_prop_name while True: # BEGIN TRANSACTION (not shown) entity = model_class.all().filter('%s !=' % metadatasig_prop_name, current_metadata_signature).get() if not entity: break setattr(entity, reference_prop_name, self) entity.update_reference_property_metadata_for_property(reference_prop_name) entity.put() # END TRANSACTION def update_reference_property_metadata_for_property(self, prop_name): # Implementation not shown, but assume this method also # updates the {{prop_name}}_metadata_signature property. def post_put(self): if self.get_metadata_signature() != self._initial_metadata_signature from google.appengine.ext import deferred deferred.defer(self.update_collections_metadata) # Haven't tried to see if this works, but that's the idea # For the ever-so-boring Author -> Article example: class Author(db.Model, ModelCommons): name = db.StringProperty() avatar_url = db.StringProperty() permissions = db.StringListProperty() meta_property_names = ('name', 'avatar_url') # Yuck way to set the initial state. Is there a better way? def __init__(self, *args, **kwds): super(self.__class__, self).__init__(*args, **kwds) self._initial_metadata_signature = self.get_metadata_signature() class Article(db.Model, ModelCommons): title = db.StringProperty() content = db.BlobProperty() author = db.ReferenceProperty(Author, collection_name = 'articles') author_metadata_signature = db.StringProperty() author_name = db.StringProperty() author_avatar_url = db.StringProperty() pre_put(): self.update_reference_property_metadata_for_property('author') I'll also have clean-up tasks just in case the deferred task in post_put() isn't successfully added. If you've followed all that code, when this happens: author = Author(key_name = 'BillyJoel123', name='Billy Joel', avatar_url='http://whatever.com/billy.png', permissions = ['editor','admin']) author.put() article = Article(author=author, title = 'I love to sing', content='Yes I do') article.put() # Some time later... author = db.get(db.Key.from_path('Author', 'BillyJoel123')) author.avatar_url = 'http://whatever.com/anotherpic.png' author.put() Then article's "author_*" properties will (eventually) be updated without any extra intervention. So that's what I'm trying to do. It's possible right now if I choose to hard-code certain information, but as I mentioned earlier, maintaining the model design when it's big (and as it evolves) can cause headaches. I think Google App Engine should make available public methods to be able to get information about the collections for each entity and/or model class that has collections. Such collection information includes: - The collection_names for each Model class (similar to the properties() method of the db.Model class) - The reverse-referenced Model class for each collection - The property name of the ReferenceProperty of the reverse-referenced Model class This information is already available "in the background", so I can't see why it shouldn't be made publicly available. How can I make a request to have this included in future SDK versions? PS. If you've managed to read all the way down to here, thanks for taking the time to read this. :) -- 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.