Currently the GAE StringProperty will not render as a password field when used in a Django form.
This page will show you how to extend the StringProperty class so that it will, by using use the Django PasswordInput widget. While we are at it, we will also provide a way to set the SIZE, MAXLENGTH and CLASS attributes on the rendered INPUT field.
Here is the key code:
from google.appengine.ext import db
from django.newforms.widgets import PasswordInput, TextInput
class StringPropertyXtr(db.StringProperty):
def __init__(self, size=None, maxlength=None, password=False,
cssClass=None, **kwargs):
self._size = size
self._maxlength = maxlength
self._password = password
self._cssClass = cssClass
super(StringPropertyXtr, self).__init__(**kwargs)
def get_form_field(self, **kwargs):
defaults = {}
attrs={}
if self._size:
attrs['size']=self._size
if self._maxlength:
attrs['maxlength']=self._maxlength
if self._cssClass:
attrs['class']=self._cssClass
if self._password:
defaults['widget']=PasswordInput(attrs)
else:
defaults['widget']=TextInput(attrs)
defaults.update(kwargs)
return super(StringPropertyXtr, self).get_form_field(**defaults)
This new property class StringPropertyXtr has all the same functionality as StringProperty, but the constructor now has four new optional parameters:
import os
from google.appengine.api import users
from google.appengine.api import images
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.db import djangoforms
from django.newforms.widgets import PasswordInput, TextInput
class StringPropertyXtr(db.StringProperty):
def __init__(self, size=None, maxlength=None, password=False,
cssClass=None, **kwargs):
self._size = size
self._maxlength = maxlength
self._password = password
self._cssClass = cssClass
super(StringPropertyXtr, self).__init__(**kwargs)
def get_form_field(self, **kwargs):
defaults = {}
attrs={}
if self._size:
attrs['size']=self._size
if self._maxlength:
attrs['maxlength']=self._maxlength
if self._cssClass:
attrs['class']=self._cssClass
if self._password:
defaults['widget']=PasswordInput(attrs)
else:
defaults['widget']=TextInput(attrs)
defaults.update(kwargs)
return super(StringPropertyXtr, self).get_form_field(**defaults)
class Usr(db.Model):
# Use new parameters and show that existing still work.
username = StringPropertyXtr(size=20,cssClass='inputcss',
verbose_name='User name')
password = StringPropertyXtr(password=True,maxlength=10)
class UsrForm(djangoforms.ModelForm):
class Meta:
model = Usr
class TestHandler(webapp.RequestHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), 'test.html')
self.response.out.write(template.render(path, {'form':UsrForm()}))
def post(self):
form = UsrForm(data=self.request.POST)
self.response.out.write(template.render('test.html', {'form':form}))
application = webapp.WSGIApplication(
[('/test', TestHandler)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
The test.html template might look like this:
<html>
<body>
<form method="post">
<table>
{{form}}
<tr>
<td/>
<td>
<button type="submit" >Submit</button>
</td>
</tr>
</table>
</form>
</body>
</html>
This would render in the final page like this:
<html>
<body>
<form method="post">
<table>
<tr>
<th><label for="id_username">User name:</label></th>
<td><input id="id_username" type="text" class="inputcss" name="username" value="" size="20" /></td>
</tr>
<tr><th><label for="id_password">Password:</label></th>
<td><input id="id_password" type="password" name="password" value="" maxlength="10" /></td>
</tr>
<tr>
<td/>
<td>
<button type="submit" >Submit</button>
</td>
</tr>
</table>
</form>
</body>
</html>
Try it out live here