views:

54

answers:

2
        votergroup = db.GqlQuery("SELECT * FROM Voter WHERE lastname = :1", 'AGEE')

    for voter in votergroup:
        voter.email = '[email protected]'
    db.put(votergroup)

The above code doesn't seem to be updating the records as it shows in the appengine documentation. I also tried using a query object to no avail. I know votergroup is pulling records, because I did a count on the object when debugging and it showed 10 records. In fact, before the db.put, I looped through voter.email, and it seems like the variable was set. However, the change never seems to make it back to the db.

Does anyone know what I might be doing wrong?

A: 

Try this instead:

votergroup = db.GqlQuery("SELECT * FROM Voter WHERE lastname = :1", 'AGEE')

for voter in votergroup:
    voter.email = '[email protected]'
    voter.put()

I don't think there is a way to do mass edits with the app engine.

WoLpH
`put()` takes a list of entities, and persists them all: http://code.google.com/appengine/docs/python/datastore/functions.html#put
Jason Hall
@Jason Hall: I stand corrected. Last time I tried something like that it simply didn't work and i wasn't able to find it in the docs.
WoLpH
+1  A: 

You need to call fetch() on the query you create with db.Query() to have it return a list of entities. You can then call put(list_of_entities) to persist them all. That looks like this:

voters = db.GqlQuery("SELECT * FROM Voter WHERE lastname = :1", 'AGEE').fetch(10)

for voter in voters:
    voter.email = '[email protected]'
db.put(voters)

If you don't call fetch() on the query, you can still iterate over the results, and a datastore RPC will be made to retrieve small batches as they are needed. Calling put() on the query doesn't do anything, but you can still perform actions on each entity inside the loop.

voters_query = db.GqlQuery("SELECT * FROM Voter WHERE lastname = :1", 'AGEE')

for voter in voters_query:
    voter.email = '[email protected]'
    voter.put()

Note that this does one datastore calls for each entity, plus one call for each batch being iterated over. It's much better to use fetch() unless you don't know how many items will be returned.

You can use cursors to break fetches up into larger chunks. I believe, though I can't find any proof, that fetch() has a limit of 1000 entities.

Jason Hall
That's so peculiar - so is the appengine documentation wrong? Check this out: https://code.google.com/appengine/docs/python/datastore/creatinggettinganddeletingdata.htmlAbout halfway down you'll see the example code that I mimickedif users.get_current_user(): user_pets = db.GqlQuery("SELECT * FROM Pet WHERE owner = :1", users.get_current_user()) for pet in user_pets: pet.spayed_or_neutered = True db.put(user_pets)
etc
That looks like a typo. Later on in the GqlQuery section (https://code.google.com/appengine/docs/python/datastore/creatinggettinganddeletingdata.html#Getting_Entities_Using_a_Query) they use `fetch()` before iterating over `results`.
Jason Hall
Is there any way to have a limitless "fetch". In this circumstance there were only 10 records, but I really don't want to necessarily limit it. Is my only option breaking it off into smaller jobs, like mapper?Thank you so much btw. I banged my head for almost 4 hours trying to figure out what in the hell I was doing wrong. How aggravating! I wonder who I would speak to about getting that documentation fixed - it would seem to me that this page would be one of the most referenced parts of the documentation.
etc
Updated my answer to be a much more complete answer. Short answer: use cursors.
Jason Hall
minor nitpick: an RPC won't be made for each iteration; entities are fetched in small batches. I believe you'll get an RPC for each 10 iterations.
Wooble
@Wooble Good to know. The `put()` inside the loop will still be called for each iteration though, so using `fetch()` is still a much better option.
Jason Hall
One error: calling db.put() on a Query doesn't do nothing - it's worse than nothing. It'll iterate over every result the query has to return, storing them all back to the datastore unmodified!
Nick Johnson
Also, the 1000 entity limit on fetch() was removed a few releases ago (although you can still get a DeadlineExceeded fetching too many entities at once...)
Wooble
@Nick wow, that seems...bad. Shouldn't it at least do nothing, or better yet raise an error?
Jason Hall
@Jason No, because passing an iterator to db.put is a perfectly valid operation - for example, if you had a generator function that produces entities to be stored.
Nick Johnson