Issue: Create a method that verifies if username
exists when Creating an Account, deny account if username
exists, and advises the user to create a new username
and repeat the process should need be.
I have some idea of how to do this based on some STACKS questions (1, 2) that I have read on here. Such as something like:
- Send the username to the server.
- Check for the existence of the username in the Database.
- Respond to the client with true or false depending on the presence of the username.
- Based on the response, send the user a client side alert!
I am uncertain how to properly execute the process in the Sign Up Page (also known as the Create an Account
page) using Pyramid and SQLAlchemy. Since I am newbie, I want to make sure I am creating code that is fast, efficient and with smart design. I want to ensure I am staying within best practices.
Right now in the User
database, Username
is UNIQUE
; this causes the system to crash when a user tries to create a username
that exists in the db. My code is missing something as there is a traceback that indicates DETAIL: Key (username)=(baseball) already exists.
Any help or suggestions is truly appreciated! If I have a poor method, suggestions of a better method is highly welcomed!
Software: Python 2.7, Pyramid 1.5.7, SQLAlchemy 1.0.9
views.py
(code: to the create a user page and save new user)
@view_config(route_name='create_user', request_method='GET', renderer='templates/create_account.jinja2')
def user_form_view(request):
return {}
@view_config(route_name='save_new_user')
def save_new_user(request):
with transaction.manager:
username = request.params['username']
check_username = api.retrieve_user(username) #retrieves one_user
#check_users = api.retrieve_users() #this retrieves ALL the users
taken = False
for user in check_username: #prints out all user info
if username == user.username:
taken = True
break
if taken:
username = request.params['username']
password = request.params['password']
firstname = request.params['firstname']
lastname = request.params['lastname']
email = request.params['email']
new_user = api.create_user(username, password, firstname, lastname, email)
new_account = api.update_group_add_user('Registered User', new_user)
transaction.commit()
return HTTPSeeOther(location=request.route_url('login'))
Traceback:
IntegrityError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (psycopg2.IntegrityError) duplicate key value violates unique constraint "users_username_key"
DETAIL: Key (username)=(baseball) already exists.
[SQL: 'INSERT INTO users (username, firstname, lastname, email, password, institution, created_on) VALUES (%(username)s, %(firstname)s, %(lastname)s, %(email)s, %(password)s, %(institution)s, %(created_on)s) RETURNING users.id'] [parameters: {'username': u'baseball', 'firstname': u'jlo', 'lastname': u'lo', 'institution': None, 'created_on': datetime.datetime(2015, 11, 24, 22, 27, 20, 286260), 'password': '78d8045d684abd2eece923758f3cd781489df3a48e1278982466017f', 'email': u'j'}]
Where should I create the function validate_registration -- outside of the registration_view function? Should this be a Boolean
statement? Is this the best method? Where would transaction.commit()
exist?
View Code with GET and POST:
def validate_registration_form(request):
with transaction.manager:
username = request.params['username']
check_username = api.retrieve_user(username)
password = request.params['password']
firstname = request.params['firstname']
lastname = request.params['lastname']
email = request.params['email']
if check_username is not None:
return False
else:
return True
@view_config(route_name='registration', renderer='templates/create_account.jinja2')
@view_config(route_name='save_registration', renderer='templates/create_account.jinja2')
def registration_view(request):
if request.method == 'GET':
return {} # render the empty form
elif request.method == 'POST':
if validate_registration_form(request): #save new_user and redirect
new_user = api.create_user(username, password, firstname, lastname, email)
new_account = api.update_group_add_user('Registered User', new_user)
transaction.commit()
raise HTTPSeeOther(location=request.route_url('login'))
else:
# form is not valid, re-render the form
# with the data user entered and an error message
return {
'error_message': 'username already taken',
'username': request.POST.get('username', ''),
'password': request.POST.get('password', ''),
'firstname': request.POST.get('firstname', ''),
'lastname': request.POST.get('lastname', ''),
'email': request.POST.get('email', '')
}
form:
<form action="/save_registration" method="POST">
<div class="form-group">
<dl>
<dt><label for = 'username'> Username: <em>single word--no spaces</em> </label></dt>
#more ....
Well, the classic approach to server-side form validation on submit is something like this (in pseudocode):
@view_config(route_name='registration', renderer='my_rego_form.jinja2') # handles both GET and POST
def rego_form(request):
if request.metod == 'GET':
return {} # render the empty form
elif request.method == 'POST':
if validate_rego_form(request):
# create a new user and redirect elsewhere
create_user(request)
raise HTTPFound('/post_registration_page')
else:
# form is not valid, re-render the form
# with the data user entered and an error message
return {
'error_message': 'Error creating user',
'username': request.POST.get('username', '')
'email': request.POST.get('email', '')
'phone_num': request.POST.get('phone_num', '')
}
else:
# some other HTTP method, not sure how to deal
So, basically, the form needs to be able to re-render itself with the data submitted by the client.
The validation method itself can be trivial and just check for the user with the given email in the db. Or, as you tried to do, instead of pre-validation you can try to just create a record and handle the exception if one occurs.