用户表单和条件的服务器端预验证(Design/Best 实践)

Server-Side PreValidation of User Form and Conditionals (Design/Best Practice)

问题:创建一个方法,在 创建帐户 时验证 username 是否存在,如果 username 存在则拒绝帐户,并建议用户创建一个新的 username 并重复该过程应该需要。

根据我在此处阅读的一些 STACKS 问题 (, 2),我对如何执行此操作有了一些想法。比如:

  1. Send the username to the server.
  2. Check for the existence of the username in the Database.
  3. Respond to the client with true or false depending on the presence of the username.
  4. Based on the response, send the user a client side alert!

我不确定如何使用 PyramidSQLAlchemy 在注册页面(也称为 Create an Account 页面)中正确执行流程。由于我是新手,我想确保我正在创建快速、高效且设计巧妙的代码。我想确保我遵守最佳实践。

现在在 User 数据库中,UsernameUNIQUE;当用户尝试创建数据库中存在的 username 时,这会导致系统崩溃。我的代码缺少一些东西,因为有一个回溯表明 DETAIL: Key (username)=(baseball) already exists. 非常感谢任何帮助或建议!如果我有一个不好的方法,非常欢迎提出更好的方法的建议!

软件:Python2.7、Pyramid 1.5.7、SQLAlchemy 1.0.9


views.py
(代码:创建用户页面并保存新用户)

@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'))

回溯:

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'}]

根据以下建议更新

问题:

我应该在哪里创建函数 validate_registration -- 在 registration_view 函数之外?这应该是 Boolean 语句吗?这是最好的方法吗? transaction.commit() 会存在哪里?

使用 GET 和 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 action="/save_registration" method="POST">
        <div class="form-group">
            <dl>
                <dt><label for = 'username'> Username: <em>single word--no spaces</em> </label></dt>
      #more ....

嗯,提交时服务器端表单验证的经典方法是这样的(伪代码):

@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

因此,基本上,表单需要能够使用客户端提交的数据重新呈现自身。

验证方法本身可能很简单,只需在数据库中检查具有给定电子邮件的用户。或者,正如您尝试做的那样,您可以尝试只创建一条记录并在发生异常时处理异常。