my first question here, perhaps a noob question but I really don't understand what I'm doing wrong, and I can't find any clue on the web.py documentation.
Is it possible to use a db select to validate a field?
What I'm doing:
I'm building a registration form, I'm having trouble with the username validation.
In every example I found, users are declared in a variable before the registration Class with code like this:
allowed = (
('jon','pass1'),
('tom','pass2')
)
and used in the validation like this:
form.Validator('Username already exists.', lambda x: x not in allowed)
Since I'm saving in db, I can change the allowed tuples with a db.select, but this mean the select is performed only once.
I want to check the users every time the POST is called, so I just replaced the "allowed" variable with a db.select this way:
form.Validator('Username already exists.', lambda x: x not in [o.usr for o in db.select('users',what='usr')])
If I test "x not in [o.usr..etc..etc..]" on the interpreter, this work..
>>> [o.usr for o in db.select('users',what='usr')]
0.0 (1): SELECT usr FROM users
[u'hhh', u'Fede', u'Vinz', u'Patro', u'Codino', u'Codino']
>>> x = "Fede"
>>> x not in [o.usr for o in db.select('users',what='usr')]
0.0 (2): SELECT usr FROM users
False
But when I run the code and I make a new registration with an existing username nothing happens.. as you can see the "Codino" username is been registered twice.
What I'm doing wrong?
..and more interesting: there is a smarter way to block the registration of an already used username?
Thanks,
Federico
I don't know if you already have an answer with this one since it's an old thread.
Here's what I did on checking if username already exist.
I create a validator such as these:
vuser_exist = form.Validator("Username already exist.", lambda u: u is None or model.get_user(u.username) is None)
register_form = form.Form(
form.Textbox("username", vuser_req, vuser_length, description="Username"),
form.Button("submit", type="submit", description="Register"),
validators = [vuser_exist],
)
In model.py
def get_user(user):
try:
return db.select('users', where='user=$user', vars=locals())[0]
except IndexError:
return None
Related
Very basically I have a model member and want to restrict searching members to allowed users. I use the following in the corresponding view
if request.user.has_perm('view_member'):
context['user_list'] = get_user(q)
Sadly this does not work even if
a) I give a user this permission via the admin interface
b) in my tests that look a bit like the following
def test_user_search_view(self):
self.client.login(username='testuser0', password='12345') # this is a user that was given the permission (see below)
response = self.client.post(reverse('library:search'), data={'q': "Müller"})
# Check our user is logged in
self.assertEqual(str(response.context['user']), 'testuser0') # Works
self.assertContains(response, "Max") # Fails, but Max should be there
For further tests I used the debugging mode of PyCharm to go into the test. In the console I then executed the following
>>> permission_view_user = Permission.objects.get(codename='view_member')
>>> test_user0.user_permissions.add(permission_view_user)
>>> test_user0.save() # For good luck
>>> user = get_object_or_404(User, pk=test_user0.pk)
>>> user.has_perm(permission_view_user)
False
I would expect true here.
I forgot the app name 🙈
It should be
if request.user.has_perm('appname.view_member'):
context['user_list'] = get_user(q)
Just to mention, English is not my native language.
So my question is, I have a form in Python/Django, that adds a simple object with name and function, example:
Function: programmer
Name: Carlos
What I want to do is to make things simple for the user when he adds several users with the same function, so I thought, when the user do something like this...
Function: programmer
Name: Dean,Seth,Roman,Ross,Joey,Chandler
...my form would add 6 objects, but the problem is that when I do this, python/django always tries to use the same ID/PK(example: tries to add all 6 members with id/pk=1).
I've done a little manuever(in Brasil we call gambiarra), so my code does this(after splitting objects):
form2.name = nombre
form2.pk = primary+1
form2.save()
primary=form2.pk
This basically consists in using this var called primary to change the value of PK and saving to Postgres. It worked, now Dean is pk/id 1....Chandler is pk/id 6, and all in one form.
But, I'm not that lucky, so when I go to add another name, like George, the system tries to use pk=2.
Does anyone knows to resolve this thing without this manuever or how to improve this manuever to solve completely?
My code (just to remind, I'm a python beginner):
objnet = form.save(commit=False)
if ',' in objnet.netaddr:
listaips = objnet.netaddr.split(',')
codeon = 1
nomecomum=objnet.nome
for ip in listaips:
objnet.netaddr = ip
objnet.nome = nomecomum + "_" + str(codeon)
objnet.save()
codeon+=1
else:
objnet.save()
Explanation:
I have a form with an IP field(netaddr) and a char field(nome)....if contains a ',' in IP field, it will add more than one object, example:
nome = carlos
netaddr = 2.2.2.2,3.3.3.3
it should add carlos_1 in my DB with IP 2.2.2.2, and carlos_2 with IP 3.3.3.3. And the code really does that, but, he adds carlos_1 and then, he tries to add carlos_2, he does with the same PK, so instead of adding another element, he overwrites carlos_1, so in my DB now there's only carlos_2.
Thank you
You have such problem because objnet always link to one object (since form.save() returns object)
Quick fix:
if ',' in objnet.netaddr:
listaips = objnet.netaddr.split(',')
codeon = 1
for ip in listaips:
objnet = form.save(commit=False)
objnet.netaddr = ip
objnet.nome = objnet.nome + "_" + str(codeon)
objnet.save()
codeon+=1
else:
form.save()
I am trying this form a while. I have a page which displays a form and whose databse definition looks like:
db.define_table('nskrelease',
Field('sprid',length=128,requires=IS_IN_SET(['R3.2', 'R3.3', 'R3.4'],zero=T('choose one'),error_message='must be R3.2 or R3.3 or R3.4 '),label = T('SPR')),
Field('releaseid',length=128, requires = IS_NOT_EMPTY(error_message='Release ID cant be empty'),label = T('Release')),
Field('coordinator',requires=IS_EMAIL(error_message='invalid email!') ,label=T('Co-ordinator Email')),
Field('startdate', 'datetime', default=request.now,requires = IS_NOT_EMPTY(error_message='Start date cant be empty'), label=T('Start date')),
Field('enddate', 'datetime', default=request.now, requires = IS_NOT_EMPTY(error_message='End date cant be empty'), label=T('End Date')),format='%(%releaseid)s')
db.nskrelease.releaseid.requires = IS_NOT_IN_DB(db,'nskrelease.releaseid')
db.nskrelease.coordinator.requires = IS_IN_DB(db,'auth_user.email','%(email)s')
But the problem here is the Coordinator field displays all the user in present in db.auth_user. Instead i need that to be restricted only to the Logged in user. So I tried:
db.nskrelease.coordinator.requires = IS_IN_DB(db(db.nskrelease.coordinator == 'auth.user.email'))
But it gives me error:
TypeError: __init__() takes at least 3 arguments (2 given)
Please help. Thanks in advance.
If the only email address allowed in this field is that of the currently logged in user, then maybe just set that as the default value and don't make the field writable:
Field('coordinator', writable=False,
default=auth.user.email if auth.user else None,
update=auth.user.email if auth.user else None)
However, a better approach might be to make this a reference field, so you don't have to worry about updating this field whenever there is a profile update:
Field('coordinator', 'reference auth_user', writable=False,
default=auth.user_id, represent=lambda v, r: v.email)
I have a User model and there is a password columns(PasswordType), amongst many other columns. When I try to do this
user = # get some user with some query
print(user.password)
# there is a password
user.password = 'something else'
db.session.is_modified(user)
# True
db.session.commit()
print(user.password)
# prints new password
user.password = None
db.session.is_modified(user)
# True
db.session.commit()
print(user.password)
# This correctly prints None
# Now the funny part,
user.password = 'something new again'
db.session.is_modified(user)
# False
db.session.commit()
print(user.password)
# Prints None again.
I've been at this for hours and can't figure out why this is happening.
The problem was with the PasswordType in SQLAlchemy-utils.
It works when I make a call to force_auto_coercion.
This may answer to your question: check this out: http://docs.sqlalchemy.org/en/rel_0_9/orm/session_api.html#sqlalchemy.orm.session.Session.is_modified
Instances present in the Session.dirty collection may report False when tested with this method. This is because the object may have received change events via attribute mutation, thus placing it in Session.dirty, but ultimately the state is the same as that loaded from the database, resulting in no net change here.
You may also wanna use this as for the state management utilities (in order to know which state your instance is in).
>>> from sqlalchemy.orm.util import object_state
>>> print object_state(instance)
Ok this one should be an easy question id imagine, but cannot figure it out.
Im passing form data to the controller and attempting to do a data search there, which in turn, runs this..
def initLogin():
userName = request.vars.user_name;
counter = db(db.Users.UserName == userName).count()
if counter > 0:
return DIV("User exists")
return DIV("user does not exist")
I have checked the value is being passed correctly( which is is) by returning userName instead of the string, which shown me it was the correct value, and when i had a direct string of a correct username, it seemed to work. So my question is.. how do you run a count() function with web2py databases correctly using variables?
Your code is correct and shouldn't be giving you any problems, the only possible problem should be in your userName var not being what you expected or an incorrect sql query. I recommend that you try changing your controller to:
def initLogin():
userName = request.vars.user_name;
counter = db(db.Users.UserName == userName).count()
lastExecutedQuery = db._lastsql
return DIV( lastExecutedQuery )
And check if the query being performed is the one that you expected.