I'm having what seems like a very strange problem with an Entity relationship in the google app engine data store. I'm work on a Python/GAE webapp (learning exercise), the full code to which can be found on sourceforge.
- I have 2 models:
- Gallery - a search term and (indirectly) a list of photos
- Photo - information about a photo, plus the gallery it belongs to (collection_index='photos')
- I have an ingestion process that creates galleries and adds photos to them
- I have a page that reads a gallery from the datastore and uses the ".photos" attribute of that Gallery instance to get the list of photos in it
Now this is where the weird part comes in... If I change a file (any file I've tested on) or even just update the timestamp of the file (ie, so it gets reloaded)... the ".photos" attribute of galleries starts failing. For example, if I try开发者_Python百科 to load the page for the "flowers" gallery:
Traceback (most recent call last):
File "C:\Applications\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 700, in __call__ handler.get(*groups)
File "C:\Eclipse-Workspace\galleries-google\app\views\gallery.py", line 33, in get for photo in gallery.photos:
AttributeError: 'Gallery' object has no attribute 'photos'
I can restart the webapp, I can restart the app launcher and then start the webapp. The problem persists regardless of this. It seems I need to force the datastore to "remember" the connection in some way
# Reading the list of photos for a given gallery via the Photo entity
# This seems to force the datastore to "remember" the connection between the two
from google.appengine.ext import db
import pprint
from app.models.gallery import Gallery
from app.models.photo import Photo
gallery = Gallery.get_by_key_name('candy')
print("Gallery: " + gallery.search_term)
q = db.GqlQuery("SELECT * FROM Photo WHERE gallery = :1", gallery )
photos = q.fetch(20)
for photo in photos :
print("\tphoto: " + photo.getUrl('original'))
or by re-ingesting all the data from scratch (though I suppose even just re-ingesting a single gallery would do).
Does anyone have any thoughts as to what might be causing this? Any help would be appreciated.
Notes:
- This is in the dev environment. I haven't gotten to the point where it's worth registering it as a webapp on the real servers yet.
- Oddly enough, I recently asked a question on how to How to list child nodes in parent in GAE... since I really wanted the information to exist in the parent model definition. Ironic that it's (apparently) a lack of that information in the parent that's causing a problem now
So, after much digging around, I believe I found an answer...
- When a file is modified (the timestamp changes), the app engine invalidates the compiled/cached files it has
- When the
Photo
class is defined, it adds a property to theGallery
based on the collection of ids it has for them
- When it needs the
Gallery
class, the app engine reloads the code for it... because it's definition was invalidated by a file being modified - Since it doesn't know it needs the
Photo
class, it doesn't load that file, so the "new instance" of theGallery
class doesn't have the property that should be created for it's collection
My first solution was to add a dependency on the Photo
file in the Gallery
file.
from app.models.photo import Photo
The problem with this is that it creates a circular dependency between the two files (since Photo already needs to know about Gallery in order to have a list of them). While it worked, I was told that Python has "problems" with circular dependencies, and it's probably not a good thing to do; it may come back to bite me later.
The solution I wound up going with was to have the __init.py file for the package in question include a dependency for both files. As such, any time either one of the files is needed, both will be loaded.
精彩评论