views:

225

answers:

2

Background

So let's say I'm making app for GAE, and I want to use API Hooks.

BIG EDIT: In the original version of this question, I described my use case, but some folks correctly pointed out that it was not really suited for API Hooks. Granted! Consider me helped. But now my issue is academic: I still don't know how to use hooks in practice, and I'd like to. I've rewritten my question to make it much more generic.


Code

So I make a model like this:

class Model(db.Model):
    user = db.UserProperty(required=True)
    def pre_put(self):
        # Sets a value, raises an exception, whatever.  Use your imagination

And then I create a db_hooks.py:

from google.appengine.api import apiproxy_stub_map

def patch_appengine(): 
    def hook(service, call, request, response):
        assert service == 'datastore_v3'
        if call == 'Put':
            for entity in request.entity_list():
                entity.pre_put()

    apiproxy_stub_map.apiproxy.GetPreCallHooks().Append('preput',
                                                        hook,
                                                        'datastore_v3')

Being TDD-addled, I'm making all this using GAEUnit, so in gaeunit.py, just above the main method, I add:

import db_hooks
db_hooks.patch_appengine()

And then I write a test that instantiates and puts a Model.


Question

While patch_appengine() is definitely being called, the hook never is. What am I missing? How do I make the pre_put function actually get called?

+1  A: 

I don't think that Hooks are really going to solve this problem. The Hooks will only run in the context of your AppEngine application, but the user can change their nickname outside of your application using Google Account settings. If they do that, it won't trigger any logic implement in your hooks.

I think that the real solution to your problem is for your application to manage its own nickname that is independent of the one exposed by the Users entity.

Adam Crossland
Ah, darn, you're absolutely right. So what about enforcing uniqueness per account? Wouldn't that be done best by checking before a put?
Nick Novitski
If you want to enforce uniqueness, then you would have to check before the first put that creates the entity in the datastore. If you forbid the user from changing that value -- which is a good idea -- you only need to check on creation.
Adam Crossland
True, and in both cases, I'm just going to write a method that does the checks and updates I want before putting, then use that instead of put(). Thank you.
Nick Novitski
+1  A: 

Hooks are a little low level for the task at hand. What you probably want is a custom property class. DerivedProperty, from aetycoon, is just the ticket.

Bear in mind, however, that the 'nickname' field of the user object is probably not what you want - per the docs, it's simply the user part of the email field if they're using a gmail account, otherwise it's their full email address. You probably want to let users set their own nicknames, instead.

Nick Johnson