0

This may be more of a general python question than an AppEngine specific question. I'm having trouble with determining if my Google AppEngine GQL query returns an object or not. I'm new to AppEngine and python, so this may be a simple question

I am using the python code:

user = db.GqlQuery("SELECT * FROM UserStore WHERE user_id = 1234567890")

To check and see if there is a user returned, I've been trying:

if(user in locals()):
  self.response.out.write('User Exists: ' + user.user_id)
  return
else:
  CreateTheUser()

But I'm thinking now this is not the best way. Is there a better way to tell if a user (or a list of users) has been returned by the db.GqlQuery statement?

Brett
  • 11,637
  • 34
  • 127
  • 213
  • `if user in locals()` doesn't do what you're expecting for several reasons. First, checking against `locals()` will tell you if the variable is defined - which it always will be, since you just assigned to it. Second, you're actually checking if the _value_ of the user variable exists as a key in locals - what you're trying to do should be `if 'user' in locals():`. Eg, `foo='hello'; foo in locals()` is equivalent to `'hello' in locals()`, _not_ to `'foo' in locals()`! – Nick Johnson Jul 20 '12 at 07:09

3 Answers3

1

try this, I think the value of user will be None if the query doesn't return anything:

if user is not None:      #or simply `if user`
    #do something
else:
    #do something else
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • `if user` is more than enough in this case. – aschmid00 Jul 13 '12 at 18:01
  • I don't know. I find `if user is not None` is more obvious and readable than `if user`. It's just a matter of taste, but shorter isn't always better. – Adam Crossland Jul 13 '12 at 18:13
  • no its not. `not None` checks only if its not a `NoneType`, `if user` would evaluate to `False` with empty string, empty list, empty dictionary... and of course its more generic than checking on a NoneType so it depends on how specific you want to make your check. – aschmid00 Jul 13 '12 at 18:25
  • @aschmid00 What if user is '' (empty string)? Of course that should be checked at other places like model definitions, but being explicit is what the zen of python suggests (to choose when there are options). – 0xc0de Oct 31 '17 at 05:30
1

From your example

user = db.GqlQuery("SELECT * FROM UserStore WHERE user_id = 1234567890")

will always return a query object e.g. <google.appengine.ext.db.Query object at 0xab71f6c> .

To evaluate the returned result you need to use .get(), .fetch(), - run() would give you QueryIterator.

So currently your comparison of

user = db.GqlQuery("SELECT * FROM UserStore WHERE user_id = 1234567890")
if user:
  # do something

or

user = db.GqlQuery("SELECT * FROM UserStore WHERE user_id = 1234567890")
if user not None:
  # do something

will always pass as user will not be None ever.

In this specific example you would probably use user = db.GqlQuery("SELECT * FROM UserStore WHERE user_id = 1234567890").get() as you only expect one result. Then do the if user: comparison.

If you use fetch() you will get a list back. Which might be useful if you want to confirm no more than one user exists. (Not sure how you are managing your unique constraint on user_id, but that is a separate question ;-)

Tim Hoffman
  • 12,976
  • 1
  • 17
  • 29
0

Try using try:

try:
    self.response.out.write('User Exists: ' + user.user_id) 
except AttributeError:
    CreateTheUser()

This approach will try to output the user details and if the attribute is undefined for the user object then you will get an AttributeError. You can also use Exception which captures all built-in, non-system-exiting exceptions.

EAFP:

Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.

LBYL:

Look before you leap. This coding style explicitly tests for pre-conditions before making calls or lookups. This style contrasts with the EAFP approach and is characterized by the presence of many if statements.

In a multi-threaded environment, the LBYL approach can risk introducing a race condition between “the looking” and “the leaping”. For example, the code, if key in mapping: return mapping[key] can fail if another thread removes key from mapping after the test, but before the lookup. This issue can be solved with locks or by using the EAFP approach.

Robert
  • 8,717
  • 2
  • 27
  • 34
  • why would you do a `try/except`? this would be a one liner with `Model.get_or_insert` and why not simply `if user`?! – aschmid00 Jul 13 '12 at 18:00
  • If there's a risk that the attribute might disappear, you need `locks` and/or `try/except` clauses. Checking if the variable is defined is as simple as you stated `if user`. But `user.user_id` is the desired attribute. – Robert Jul 13 '12 at 18:06
  • i understand but in this case its pretty clear that if there is a user , there is a user_id. if you would have optional properties then maybe you are right. in this case this really does not look good to me. sorry – aschmid00 Jul 13 '12 at 18:13
  • 1
    I think this is one that we'll have to agree to disagree then. I'm more than open to supportive information on your opinion. I think @Tim Pietzcker provides a good justification for which to use: http://stackoverflow.com/a/1835844/879199. There is also http://stackoverflow.com/questions/204308/checking-for-member-existence-in-python which addresses which one. – Robert Jul 13 '12 at 18:16
  • Try - except block is for exceptions, not for checking (legitimate) conditions. Besides an `if-else` is much more readable, concise and efficient. – 0xc0de Oct 31 '17 at 05:33