self.response.out.write("""<form action="/login" method="post" >""")
self.response.out.write("""<input type="text" name="user_name">User Name:</input>
Then I discovered the magic of Django templates. Django is an open-source web application framework. Apparently it features "...an object-relational mapper which mediates between data models (defined as Python classes) and a relational database, a regular-expression-based URL dispatcher, a view system for processing requests, and a templating system." (source Wikipedia). My group only used the templating system, which is include in the Google
webapp
module. For you to get started with Django templates in the Google App Engine infrastructure, this is what you need to know:
First of all, add the following two import statements to your Python file.
import os
from google.appengine.ext.webapp import template
Now create your html template file, mine is called
mainTemplate.html
, in the same directory as your Python file, with the following content.
<html>
<body>
<b>Hello {{ user }}</>
<form action="/login" method="post">
{% for field in formFields %}
{{ field.printHTML }}
{% endfor %}
<input type="submit" />
</form>
</body>
</html>
Now the other part of the puzzle is your actual login.py file. When we started the second sprint of the TA matching project, our top priority was to refactor our code into something that was maintainable and scalable. Part of that refactoring included adding the Django template system to our project. Another crucial part that tied into the templates very well was the creation of a Field class for all html form input fields. Basically, there are subclasses of Field for each type of input field, and each field holds:
- title text to display info about the field
- an error message to display when the input isn't valid
- the html name that's embedded in the html
- a particular Validator object that validates the input (there are many subclasses of Validator that validate specific type of input)
- a method to print the html for the field
- a method to get the user's input from the request
Let's look at the login.py file section by section:
- import statements (already gone over this)
- constructor
class MainPage (webapp.RequestHandler) :
def __init__ (self) :
# holds all the Fields for the form
self.formFields = []
self.user = ""
# -----
# login
# -----
self.loginTextBox = Field.TextBoxField()
self.loginTextBox.fieldTitle = "Please log in"
self.loginTextBox.errorMessage = " -- Invalid login"
self.loginTextBox.htmlName = "login"
self.loginTextBox.validator = Validator.NameValidator()
self.formFields.append(self.loginTextBox)
Create the formFields list that gets linked to the html template, and add as many Field objects to it as you like (here I've only added one for simplicity).
- get method
def get (self) :
# create a dictionary of values to be referenced in the template
template_values = { 'formFields': self.formFields, 'user' : self.user }
# point to the login.html file you created
path = os.path.join(os.path.dirname(__file__), 'login.html')
# takes a file path to the template file and a dictionary
# of values, and returns the rendered text.
self.response.out.write(template.render(path, template_values))
Here's where the list of fields 'self.formFields' in my python file gets linked to 'formFields' in the html template and 'self.user' gets linked to 'user' in the html template. So when the template is evaluated,{% for field in formFields %}
gets executed just like a regular for loop in python, and{{ field.printHTML }}
references theprintHTML
attribute of each Field object. In many cases, you can also pass Google datastore model objects directly as values, and access their properties from templates.
- post method
def post (self) :
"""
Captures User input
"""
# assume all fields are valid, and set to false if one isn't valid
allFieldsValid = True
for field in self.formFields :
field.getUserInput(self.request)
field.validate()
if not field.isValid :
allFieldsValid = False
if allFieldsValid :
self.user = self.formFields[0].input
self.get()
else :
self.get()
Here I'm just processing the user's input from the text field, but note the lineself.user = self.formFields[0].input
. This line now gives real meaning to the{{ user }}
in the login.html file. If the page validates correctly, the resulting page now dynamically inserts the validated user's name into the html.
Here's the login.py file in its entirety.
# --------
# login.py
# --------
import cgi
from google.appengine.ext import webapp
# need these two lines templates to work
import os
from google.appengine.ext.webapp import template
import Field # our own Field class
import Validator # our own Validator class
class MainPage (webapp.RequestHandler) :
def __init__ (self) :
# holds all the Fields for the form
self.formFields = []
self.user = ""
# -----
# login
# -----
self.loginTextBox = Field.TextBoxField()
self.loginTextBox.fieldTitle = "Please log in"
self.loginTextBox.errorMessage = " -- Invalid login"
self.loginTextBox.htmlName = "login"
self.loginTextBox.validator = Validator.NameValidator()
self.formFields.append(self.loginTextBox)
def get (self) :
# create a dictionary of values to be referenced in the template
template_values = { 'formFields': self.formFields, 'user' : self.user }
# point to the login.html file you created
path = os.path.join(os.path.dirname(__file__), 'login.html')
# takes a file path to the template file and a dictionary
# of values, and returns the rendered text.
self.response.out.write(template.render(path, template_values))
def post (self) :
"""
Captures User input
"""
# assume all fields are valid, and set to false if one isn't valid
allFieldsValid = True
for field in self.formFields :
field.getUserInput(self.request)
field.validate()
if not field.isValid :
allFieldsValid = False
if allFieldsValid :
self.user = self.formFields[0].input
self.get()
else :
self.get()
if __name__ == "__main__":
main()
The combined use of Django templates and our own Field class together has made additions and modifications of our existing code a very rapid and streamlined process.
No comments:
Post a Comment