Reputation: 640
I have model User
and property username
with validator which validates username
for available chars, non-empty and existence in DB. So, I don't need any other checks when handling registration form for example - I just assign form's username
value to model's property and catching validation error if entered username
already exists...
But, it isn't work.
Because NDB validates property's comparison arguments too (see Property._comparison method in ndb/model.py) and it goes to endless reqursion in Query.filter(User.username == [somevalue]) and finally raises RuntimeError: maximum recursion depth exceeded
. NDB trying to validate [somevalue] with validate_username
and go to this query again and again...
It's possible to assign username to entity's ID and use User.get_by_id(), but it's needed username
to be changeable, so I need to use Query.get()
.
So it is my User
model:
class User(ndb.Model):
def validate_username(self, value):
value = str(value).strip()
# Other useful checks - length, available symbols, etc
if User.get_user(value):
raise ValueError('Username already exists')
return value
@classmethod
def get_user(cls, username):
username = str(username)
user_q = User.query()
user_q = user_q.filter(User.username == username) # Here is the problem
return user_q.get()
username = ndb.StringProperty(validator=validate_username)
For example:
# Trying to add user, get RuntimeError exception
u = User()
u.username = 'John'
What I'm doing wrong? What's the best way to solve such problem?
UPDATE to Tim Hoffman:
Thanks. Yes, I've missed prop argument, but method received prop
in self
and val
in val
arguments - thus I didn't mention this mistake. But, you've missed the key issue - you don't use query with filter in validator (User.get_user method). Try this, there is no sense function or method validator is:
def validate_username2(prop, value):
if User.get_user(value):
raise Exception('User exists!')
return value
class User(ndb.Model):
def validate_username(self, value):
if User.get_user(value):
raise Exception('User exists!')
return value
@classmethod
def get_user(self, username):
user_q = User.query()
user_q = user_q.filter(User.username == username)
return user_q.get()
# Try both please
username = ndb.StringProperty(validator=validate_username)
#username = ndb.StringProperty(validator=validate_username2)
Upvotes: 0
Views: 898
Reputation: 12986
I believe you problem is due to incorrectly defining you validator as a method and not accepting the correct arguments. See the quick example below, does work with filters.
The db, ndb, users, urlfetch, and memcache modules are imported.
dev~cash-drawer> def vla(prop,val):
... if val == "X":
... raise ValueError
... return val
...
dev~cash-drawer>
dev~cash-drawer>
dev~cash-drawer> class X(ndb.Model):
... name = ndb.StringProperty(validator=vla)
...
dev~cash-drawer> y = X()
dev~cash-drawer> y.name = "X"
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 1258, in __set__
self._set_value(entity, value)
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 1004, in _set_value
value = self._do_validate(value)
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 953, in _do_validate
newvalue = self._validator(self, value)
File "<console>", line 3, in vla
ValueError
dev~cash-drawer> y.name = "aaa"
dev~cash-drawer> y.put()
Key('X', 5060638606280884224)
dev~cash-drawer> z=X.query().filter(X.name == "aaa")
dev~cash-drawer> list(z)
[X(key=Key('X', 5060638606280884224), name=u'aaa')]
dev~cash-drawer> z=X.query().filter(X.name == "X")
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 859, in __eq__
return self._comparison('=', value)
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 847, in _comparison
value = self._do_validate(value)
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 953, in _do_validate
newvalue = self._validator(self, value)
File "<console>", line 3, in vla
ValueError
dev~cash-drawer>
Upvotes: 2