custom built login form

3,115 views
Skip to first unread message

shartha

unread,
Aug 15, 2012, 1:51:12 AM8/15/12
to web...@googlegroups.com
Hello, 
Quick question:
Instead of {{=auth.login()}}, I am using the following to be able to customize my login form. However the resulting form does not work and I cannot login with the same username/password that enable me to login if I had used {{=auth.login()}} -- I get the flash error: Invalid Login.

Could someone please tell me what's possibly going wrong? Thanks!

{{form=auth.login()}}
{{=form.custom.begin}} 
Username:
{{=form.custom.widget.username}}
</br>
Password:
{{=form.custom.widget.password}}
{{=form.custom.submit}} 
{{=form.custom.end}} 

lyn2py

unread,
Aug 15, 2012, 2:50:22 AM8/15/12
to web...@googlegroups.com
Maybe you can show us the controller code?

The controller needs to have code that looks something like:
    form=SQLFORM(db.table)
   
if form.process().accepted:
        response
.flash = 'form accepted'
   
elif form.errors:
        response
.flash = 'form has errors'
   
return dict(form=form)    

shartha

unread,
Aug 15, 2012, 3:07:49 AM8/15/12
to web...@googlegroups.com
This is the form I am using in my layout file -- thus no controller involved. I am using the {{=auth.login()}} form which comes with the framework. I define the form in the first line of the snippet I posted in my original post. Is that not the right way to go?

Yarin

unread,
Aug 15, 2012, 6:29:48 AM8/15/12
to web...@googlegroups.com
You may need to include the form's hidden fields in your view. Does {{=form.hidden_fields()}} work? See here: https://groups.google.com/d/msg/web2py/k5D19CHB2TU/9Ll7ly5ZOK4J

Anthony

unread,
Aug 15, 2012, 9:52:55 AM8/15/12
to web...@googlegroups.com
Hmm, that exact code works for me. What do you mean the form doesn't work -- just that you get the invalid login message, or is there something else wrong with the appearance or processing of the form? If you replace the code shown below with just {{=auth.login()}}, everything works fine?

Anthony


On Wednesday, August 15, 2012 1:51:12 AM UTC-4, shartha wrote:

Anthony

unread,
Aug 15, 2012, 9:53:55 AM8/15/12
to web...@googlegroups.com
You may need to include the form's hidden fields in your view. Does {{=form.hidden_fields()}} work? See here: https://groups.google.com/d/msg/web2py/k5D19CHB2TU/9Ll7ly5ZOK4J

Not necessary in this case -- form.custom.end already includes the hidden fields.

Anthony 

shartha

unread,
Aug 15, 2012, 11:45:50 AM8/15/12
to web...@googlegroups.com
I get the invalid login alert. Appearance changes but that's due to the CSS (Not my concern at this moment). I should also mention that I am not suing the css files that come with the framework (web2py.css). Could that be the reason.

Anthony

unread,
Aug 15, 2012, 11:49:20 AM8/15/12
to web...@googlegroups.com
CSS shouldn't matter. Again, to confirm, replacing your code with {{=auth.login()}} works? Where are you placing that form -- in the layout or a particular view? If the layout, do you have the same problem regardless of the page (i.e., URL) from which you log in? If a specific view, can we see the controller code?

Anthony

shartha

unread,
Aug 15, 2012, 9:42:25 PM8/15/12
to
Thanks Anthony for trying to help.

Lol, I don't know I even mentioned CSS. Just to clarify, yes, I get the "invalid login" flash alert. I put the code as posted here in my layout.html file. I have the issue regardless of the page I am on. 

This is the code as it appears in the layout:
{{if not  auth.user:}}
<div id="loginForm">
{{form=auth.login()}}
{{=form.custom.begin}} 
Username:
{{=form.custom.widget.username}}
</br>
Password:
{{=form.custom.widget.password}}
{{=form.custom.submit}} 
{{=form.hidden_fields()}}
{{=form.custom.end}} 
</div>
{{pass}}

Massimo Di Pierro

unread,
Aug 15, 2012, 9:54:13 PM8/15/12
to web...@googlegroups.com
{{=form.hidden_fields()}}
{{=form.custom.end}} 

should just be

{{=form.custom.end}} 

it includes the hidden fields.

On Wednesday, 15 August 2012 20:38:35 UTC-5, shartha wrote:
Thanks Anthony for trying to help.

Lol, I don't know I even mentioned CSS. Just to clarify, yes, I get the "invalid login" flash alert. I put the code as posted here in my layout.html file. I have the issue regardless of the page I am on. 

This is the code as it appears in the layout:
{{if not  auth.user:}}
<div id="loginForm">
{{form=auth.login()}}
{{=form.custom.begin}} 
Username:
{{=form.custom.widget.username}}
</br>
Password:
{{=form.custom.widget.password}}
{{=form.custom.submit}} 
{{=form.hidden_fields()}}
{{=form.custom.end}} 
</div>
{{pass}}


On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

shartha

unread,
Aug 15, 2012, 10:18:38 PM8/15/12
to web...@googlegroups.com
Thanks Massimo, that solved the problem! :-)

On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:
On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:
On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:
On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

Anthony

unread,
Aug 15, 2012, 10:26:16 PM8/15/12
to web...@googlegroups.com
Aside from removing the unnecessary form.hidden_fields(), what changed in your code? Isn't it otherwise the same code that wasn't working before?

Anthony

shartha

unread,
Aug 23, 2012, 12:39:47 PM8/23/12
to web...@googlegroups.com
Sorry for being out of touch. I discovered what was causing the issue initially. If I try to assign a value to the id or name attributes of any of the login form elements, the form.cust.widget will not work as expected. So if you have any insight into this, please let me know as it'd be helpful under certain circumstances to be able to do that. 


On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

Anthony

unread,
Aug 23, 2012, 2:13:44 PM8/23/12
to web...@googlegroups.com
Can you show some code or provide a little more detail regarding what you're trying to do?

shartha

unread,
Aug 24, 2012, 5:27:01 PM8/24/12
to
This is in my controller:
        registrationForm = auth.register()
        UN = registrationForm.element("#user_username")
        UN["_placeholder"] = "Username"
        UN["_name"] = "regForm_username"  # This is what causes the error.

and this is in my view:

         {{=registrationForm}}

The registraionForm does not allow me to register a new user if the line that changes the name of the #user_username id exists in the controller. Once you remove it, the registration form starts to work fine. The same occurs with the login form. If you change the name of the username or password field, it doesn't allow you to log in.


The reason I'd like to change the name of the username field is that it is the same as the one on the login form, and if you happen to have both on the same page, you may encounter issues with jQuery/Ajax functions that pass along their values.




On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

Anthony

unread,
Aug 24, 2012, 5:43:49 PM8/24/12
to web...@googlegroups.com
The problem is, you're changing the name of the field in the HTML, but the server-side data model is still expecting a variable named "username" (which is the name of the field in the database table). I suppose a workaround might be something like this in the controller (before:

    if request.post_vars.regForm_username:
        request
.post_vars.username = request.post_vars.regForm_username
    registrationForm
= auth.register()

That way, the expected "username" variable will be included in request.post_vars.

Can you show an example of a jQuery/Ajax problem with fields in different forms having the same name? Can't you just put each form inside a div with a unique id and include the id in the jQuery selectors?

Anthony


On Friday, August 24, 2012 5:23:40 PM UTC-4, shartha wrote:
This is in my controller:
        registrationForm = auth.register()
        UN = registrationForm.element("#user_username")
        UN["_placeholder"] = "Username"
        UN["_name"] = "regForm_username"  # This is what causes the error.

and this is in my view:

         {{=registrationForm}}

The registraionForm does not allow me to register a new user if the line that changes the name of the #user_username id exists in the controller. Once you remove it, the registration form starts to work fine. The same occurs with the login form. If you change the name of the username or password field, it doesn't allow you to log in.


The reason I'd like to change the name of the username field is that it is the same as the one on the login form, and if you happen to have both on the same page, you may encounter issues with jQuery/Ajax functions that pass along their values.




On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

shartha

unread,
Aug 24, 2012, 10:12:40 PM8/24/12
to web...@googlegroups.com
What you mentioned re: putting forms in separate DIV's should work with jQuery functions. But I suppose if you have two forms with fields that have the same name, if you use the web2py's Ajax function, for the second parameter of the ajax function, the value of both fields will be posted. Is that not the case?

BTW, how can you format the codes in the body of a post?


Thanks for your responses.

Anthony

unread,
Aug 24, 2012, 11:48:11 PM8/24/12
to web...@googlegroups.com
I believe the second argument of ajax() can also be a string jQuery selector, which can be a selector for an entire form, whose inputs will then be serialized and posted. Good point, though -- when the second argument is a list of field names, maybe we should allow an additional parameter to specify a scope for those fields via an additional jQuery selector.

Anthony

shartha

unread,
Aug 25, 2012, 11:33:57 AM8/25/12
to web...@googlegroups.com
Thanks Anthony, I didn't know you could use jQuery selectors for the second argument. One more question:
Is it possible to generate the remember me checkbox using the form.custom.widget, or I should create my own checkbox?


On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

Anthony

unread,
Aug 25, 2012, 5:46:28 PM8/25/12
to
On Saturday, August 25, 2012 11:33:57 AM UTC-4, shartha wrote:
Thanks Anthony, I didn't know you could use jQuery selectors for the second argument. One more question:
Is it possible to generate the remember me checkbox using the form.custom.widget, or I should create my own checkbox?

No, it's added to the form DOM after the SQLFORM is created, so it's not available in form.custom.widget. However, you can access the div that contains the checkbox and label via:

form.element('#auth_user_remember').parent

or the entire table row containing the widget via:

form.element('#auth_user_remember__row')

Anthony

shartha

unread,
Aug 25, 2012, 3:57:53 PM8/25/12
to web...@googlegroups.com
You're awesome! Thank you Anthony!


On Tuesday, August 14, 2012 10:51:12 PM UTC-7, shartha wrote:

Massimo Di Pierro

unread,
Aug 25, 2012, 4:43:23 PM8/25/12
to web...@googlegroups.com
+1

Daniele

unread,
Nov 18, 2012, 6:48:09 PM11/18/12
to web...@googlegroups.com
I'm having a similar problem. I am making a custom form with this code in the view:

{{=form.custom.begin}}
    <div class="control-group {{if form.errors['email']:}}error{{pass}}">
        <label class="control-label" for="inputEmail">Email address</label>
            <div class="controls">
                {{=form.custom.widget.email}}
            </div>
    </div>
    <div class="control-group {{if form.errors['password']:}}error{{pass}}">
        <label class="control-label" for="inputPassword">Password</label>
            <div class="controls">
                {{=form.custom.widget.password}}
            </div>
    </div>
    <div class="control-group">
        <div class="controls">
            <label class="checkbox">
                <input id="auth_user_remember" class="checkbox" type="checkbox" value="on" name="remember"> Remember me (for 30 days)
            </label><br>
            {{=form.custom.submit}}
        </div>
    </div>
    {{=form.custom.end}}

But this does not log me in for some reason. If I use just {{=form}} here, it does login as it's supposed to.
My controller looks like this:

def login():
    if auth.is_logged_in():
        redirect(URL('dashboard'))
    response.subtitle = T("Login")
    return dict(form=auth.login())

I can't figure out why it's not logging me in with the custom form..

Daniele

unread,
Nov 19, 2012, 9:18:42 PM11/19/12
to
Ah ok I just took a look at the HTML and saw that my code conflicts with what web2py is generating.
Basically there's a form within a form being constructed, so it looks like this:

<form class="form-horizontal">
    <form  action="" enctype="multipart/form-data" method="post">

To avoid this, how can I tell web2py that the login form's style has to be form-horizontal?
That way it can generate the HTML automagically.
I tried the following in my controller but it's still not working:

def login():
form = auth.login()
form['_class']='form-horizontal'
return dict(form=form)

I'd eventually also like to style the Login button and the "Remember me for X days" checkbox.

Thanks!


On Wednesday, August 15, 2012 6:51:12 AM UTC+1, shartha wrote:

Paolo Caruccio

unread,
Nov 20, 2012, 9:11:33 AM11/20/12
to web...@googlegroups.com
In order to apply attributes to a custom form you have to change form.custom.begin before.
The following code should work:

#view html
{{extend 'layout.html'}}
{{
# add class to form
form
['_class'] = "form-horizontal"
# change form.custom.begin
form
.custom.begin = XML("<%s %s>" % (form.tag, form._xml()[0]))
}}

{{=form.custom.begin}}
your content form
{{=form.custom.end}}

Moreover, if do you want a form with bootstrap layout you could simply add formstyle='bootstrap" to the form via auth.settings.formstyle argument http://web2py.com/books/default/chapter/29/09?search=auth#Settings-and-messages avoiding to customize manually the html of the form.

 def login():
    auth
.settings.formstyle = 'bootstrap'
    form
= auth.login()
   
return dict(form=form)

and in the view

{{=form}}


Il giorno martedì 20 novembre 2012 02:58:37 UTC+1, Daniele ha scritto:
Ah ok I just took a look at the HTML and saw that my code conflicts with what web2py is generating.
Basically there's a form within a form being constructed, so it looks like this:

<form class="form-horizontal">
    <form  action="" enctype="multipart/form-data" method="post">

To avoid this, how can I tell web2py that the login form's style has to be form-horizontal?
That way it can generate the HTML automagically.
I tried the following in my controller but it's still not working:

def login():
form = auth.login()
form['_class']='form-horizontal'
return dict(form=form)

I'd eventually also like to style the Login button and the "Remember me for X days" checkbox.

Thanks!


On Wednesday, August 15, 2012 6:51:12 AM UTC+1, shartha wrote:

Daniele

unread,
Nov 20, 2012, 5:49:55 PM11/20/12
to
Thanks that seems to have worked. This was totally undocumented (or if it was, it was in an obscure place because I looked quite hard for how to do this.) What does that XML("<%s %s>" % (form.tag, form._xml()[0])) line do exactly?

I've now also edited my button to the style I wanted with form.custom.submit['_class'] = "btn btn-success"

Thanks


On Wednesday, August 15, 2012 6:51:12 AM UTC+1, shartha wrote:

Paolo Caruccio

unread,
Nov 20, 2012, 8:26:30 PM11/20/12
to web...@googlegroups.com
In this group there are several discussions on this subject (i.e. https://groups.google.com/d/msg/web2py/gLTthVDhqFM/dWldB9xGavgJ)
Search for messages containing the word '_xml'

We are replacing the original form.custom.begin value with a new one within which is the '_class' attribute

From web2py code documentation in gluon/html.py (class DIV):

DIV class has a tag variable that is the tag name
FORM is a subclass of DIV and updates it
therefore, if form is an istance of FORM, form.tag will be = 'form'

_xml() is a helper for xml generation. Returns separately in a tuple:
- the component attributes
- the generated xml of the inner components
Component attributes start with an underscore ('_') and
do not have a False or None value. The underscore is removed.
A value of True is replaced with the attribute name.
Therefore form._xml()[0] returns the component attributes like '_action', '_class'

by using XML you can prevent escaping 

so,

XML("<%s %s>" % (form.tag, form._xml()[0]))

returns

'<form action="" class="form-horizontal">'
Reply all
Reply to author
Forward
0 new messages