Download this page in : in pdf, in OpenOffice odt file
Contents
- Start Here
- Install TurboGears
- QuickStart a new project
- Turbogears Overview
- First webapp: Address Book
- TurboGears in Second(II) Gear
- SqlAlchemy (SA)
- Database Connection
- create table in sqlalchemy
- controller.py, Data passing and conversion
- Direct Sql statements to a database
- Basic select()
- Advenced select()
- available functions of sqlalchemy
- insert record
- update record
- Flow Control: update,submit,save,display
- Saving table with many columns
- Saving multiple records
- sqlalchemy in virtualenv
- Session Managment
- Install Turbogears with Apache
- Turbogears API Details
- Performance
- Errors
- EXTRA
- Produce PDF Pages
- MyTube with Flex and Turbogears
- captcha widgets for a form
- Basic Way to display column data from a database
- Identity Management
- TurboGears with existing MySQL database
- Flash status Bar
- Tagging with Turbogears
- Drag and Drop Sort list
- Turbogears and Oracle
- Turbogears memory managment
- unixODBC
- Authenticating against an external password source
- Embed swf files in your turbogears code (IE, Opera, Firefox etc)
- SQLObject (SO) quick Overview
- Turbogears Specifics usage
- Other Documentation
- Common Errors
Turbogears2 documentation is located here: http://lucasmanual.com/mywiki/TurboGears2
Keywords: Tutorial, TurboGears, SqlObject, SqlAlchemy, web, python, features, Linux, windows, database, mysql, Examples, web, cherrypy, manual, easy, first time to turbogears, documentation, solutions, fixed, solved,working, pylones, python web framework, TurboGears widgets, TurboGears Forms, TurboGears controller, TurboGears model, TurboGears and sqlalchemy, TurboGears and AJAX, Turbogears Documentation, Turbogears Manual, Turbogears Howto, Turbogears how to, Turbogears faq,trubogears
Start Here
Welcome.
Please start from the beginning of this page if you are new to TurboGears.
If you are looking for something specific please go over the menu items.
If you want to view TurboGears API documentation see: TurboGears API Documentation
Short Intro To TurboGears
If it is your first time working with turbogears, this TurboGears Article will give you an overview of what is what in turbogears. It will show you how turbogears connects database, templates, javascript via python in one simple framework. Here is a copy of just Turbogears related pages Turbogears in O3 Magazine, Issue5 (copy)
Search TG docs
Just looking for specific information? Look through menu first, then try TurboGears Search engine
Install TurboGears
For Turbogears to work we need the following items.
- Turbogears.
- Sqlite, python bindings for sqlite or mysql and mysql python bindings.
We will use Linux since it is the easiest operating system to work with.
- Install turbogears
aptitude update aptitude install python-turbogears
- Install sqlite it will get used especially in really quick tg apps.
aptitude install sqlite3 aptitude install python-pysqlite2
- Install mysql and/or python binding for mysql
aptitude install mysql-server aptitude install python-mysqldb
You are ready to start your turbogears development.
QuickStart a new project
Create project
- This command will create your tg app. It will ask you for your project name, etc.
tg-admin quickstart --sqlalchemy
- After running the command you should see questions like this:
Enter project name: myfirstproject Enter package name [myfirstproject]
- When done it will create folder called 'myfirstproject'
Start the project
- To start a project you just run a start file.
Go into the turbogears folder and start your project. Replace myfirstproject with your project name.
python start-myfirstproject.py
After you start it go to your internet browser and go to this website. Your app is running in a turbogears test server at http://localhost:8080
Make changes
Just go into your project folder, inside there should be:
- dev.cfg - where you set configuration properties for your project.
- setup.py - which you can use to install your python project into python site-package
- myfirstproject folder - There is a folder with a same name as your project, inside there are:
- templates - which hold all your html templates (welcome.kid)
- static - which holds your images, css, and javascript
- config- where you will find your app specific configuration.
- model.py - which has your data models
- controller.py - which has your data manipulations, your urls, etc.
You can start by editing the main page. In my case I go to myfirstproject/templates and in there you can find the welcome.kid . It is an xhtml file so you can change some text and see how they show up immediately in http:localhost:8080.
Turbogears Overview
Add,remove URL in controller.py
- Methods in your controllers.py file map directly to URL.
- In your projects' folder there is a file called controllers.py. In there you should see a code that looks like:
@expose(template="myfirstproject.templates.welcome")
def index(self):
import time
# log.debug("Happy TurboGears Controller Responding For Duty")
return dict(now=time.ctime())
First Line. You can reach index page which uses templates.welcome when you visit the http://localhost:8080
Second line. You can access this url. To create url with ending hello http://localhost:8080/hello, add the following lines.
Define a function hello and you will need hello.kid in your template folder.
@expose(template="myfirstproject.templates.hello")
def hello(self):
import time
# log.debug("Happy TurboGears Controller Responding For Duty")
return dict(greeting="Hello from a controller.py")
Database settings
- Edit dev.cfg and where you see the sqlalchemy.dburi replace it with your settings.
- You can use the default or comment it out and use some of the other examples that they have provided. mysql, sqlite, etc.
sqlalchemy.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite"
If you want to use a true database from a start you can use syntax like this for:
sqlalchemy.dburi="mysql://username:password@hostname:3306/databasename" sqlalchemy.dburi="postgres://username:password@hostname/databasename sqlalchemy.dburi="oracle://username:password@hostname:1521/sidname" sqlalchemy.dburi="mssql://username:password@hostname:1433/databasename?driver=TDS"
You don't have to provide the port as sqlalchemy knows default ports.
Database tables using model.py
- Now that we know where the database is, lets create few tables.
- Before you start change the first line, because that will allow you to differentiate different components in sqlalchemy.
- Change:
from sqlalchemy import * to import sqlalchemy
- You do it in model.py. Add something similar to this one class.
address_table = sqlalchemy.Table('address', metadata,
sqlalchemy.Column('Address_Sid', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('FirstName', sqlalchemy.Unicode(40),nullable=False),
sqlalchemy.Column('LastName', sqlalchemy.Unicode(40),nullable=False),
sqlalchemy.Column('MaidenLastName', sqlalchemy.Unicode(40)),
sqlalchemy.Column('Email', sqlalchemy.Unicode(80),nullable=False),
sqlalchemy.Column('Address', sqlalchemy.Unicode(80),nullable=False),
sqlalchemy.Column('City', sqlalchemy.Unicode(80),nullable=False),
sqlalchemy.Column('State', sqlalchemy.String(2),nullable=False),
sqlalchemy.Column('ZipCode', sqlalchemy.Integer,nullable=False),
sqlalchemy.Column('DOB', sqlalchemy.Date(),nullable=False),
sqlalchemy.Column('CreatedDate', sqlalchemy.Date, default=datetime.now().date()),
sqlalchemy.Column('CreatedTime', sqlalchemy.Time, default=datetime.now().time())
)
- Save and exit. Now that model.py has its first table lets create it in our database.
SqlAlchemy: Database tables are classes, rows are instances, fields are attributes
- To create actual database in sqlite,mysql,postgres, etc issue this command.
tg-admin sql create
Kid template
- Kid template is a set of xml files in which you are able to replace text,tags, etc. All kid files need to be a valid xml, xhtml files.
- To replace text in kid template you can do few things.The most simplest one is to define a variable. In this example we define it in template. In normal use this variable would be passed into the template from controller.py.
- Options on replacing text are:
py:content -Replace content inside of a tag <a py:content> replace this text</a> py:if -Do if statement: py:if="x" if x is true display, else it will remove the tag and its children. py:for -Do for loop py:replace -Replace whole tag: <a py:replace="<a> my default meta tag</meta>"\> py:strip py:match -Matches a tag in a template and replaces with the content you specify.(headers,footers) py:def
- Example: Replace Text
<?python myvariable = 'i want this text to replace the variable name in template' ?> <span py:content="myvariable">Text to be replaced</span>
- Replace from file:
<div py:content="document('header.html')">Replace this text</div>
Replace whole tag. This line will replace the whole meta tag with a value we have it, aka. So if you use this line to your template, the meta tag won't appear in the final output of the page.
<meta content="text/html";charset=UTF-8" http-equiv="content-type" py:replace="''"/>
- For loop
<ul>
<li py:for="person in PhoneBook">
<a href="$person.home_page">
<span py:content="person.last_name">Name to be replaced</span>,
<span py:content="person.first_name">Name to be replaced</span>
</a>
- If statement:
<div py:if="person.first_name and person.last_name" >
<span py:content="person.last_name">Name to be replaced</span>,
<span py:content="person.first_name">Name to be replaced</span>
</div>
or
<div py:if="value_of('somefield', None)" py:content="somecontent"></div>
or
<p py:if="5 * 5 == 25"> Python seems to be handling multiplication okay. </p>
First webapp: Address Book
- Create a new project.
tg-admin quickstart --sqlalchemy
- Now open a dev.cfg and add your database information in there, follow the example connection string they have in there.
- Or pick one of these:
sqlalchemy.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" sqlalchemy.dburi="mysql://username:password@hostname:3306/databasename" sqlalchemy.dburi="postgres://username:password@hostname/databasename sqlalchemy.dburi="oracle://username:password@hostname:1521/sidname" sqlalchemy.dburi="mssql://username:password@hostname:1433/databasename?driver=TDS"
You don't have to provide the port as sqlalchemy knows default ports.
- You are done with your app connection to a database. Sqlalchemy/Turbogears will take it from here.
Database Model
- Model.py handles the definitions of all your data.
- It is here where you define your tables, data models, anything that needs a definition.
Before we start lets make sure you have all modules imported and you know what is for what.
- Make sure you imported proper modules.
- Define your tables. 1.Create and bind your database to python class.
Import Proper Modules
- You should see an import statements like this(if you don't need identity this list will be shorter):
from datetime import datetime #this imports date and time manipulation library from turbogears.database import metadata, mapper #This maps database to a python class (more on it soon) # import some basic SQLAlchemy classes for declaring the data model # (see http://www.sqlalchemy.org/docs/04/ormtutorial.html) from sqlalchemy import Table, Column, ForeignKey from sqlalchemy.orm import relation # import some datatypes for table columns from SQLAlchemy # (see http://www.sqlalchemy.org/docs/04/types.html for more) #from sqlalchemy import String, Unicode, Integer, DateTime,Time,Date, TEXT import sqlalchemy from turbogears import identity
Create Tables
- Its time to create your table now.
- With sqlalchemy you have choice of either defining your own table or loading already existing table from database.
- The database you are connecting is defined in dev.cfg.
Define a table
#Your table definition here.
address_table = sqlalchemy.Table('addressbook', metadata,
sqlalchemy.Column('Address_Sid', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('FirstName', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('LastName', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('MaidenLastName', sqlalchemy.Unicode(40)),
sqlalchemy.Column('Email', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('Address', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('City', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('State', sqlalchemy.String(2),nullable=False),
sqlalchemy.Column('ZipCode', sqlalchemy.Integer,nullable=False),
sqlalchemy.Column('DOB', sqlalchemy.Date(),nullable=False),
sqlalchemy.Column('CreatedDate', sqlalchemy.Date, default=datetime.now().date()),
sqlalchemy.Column('CreatedTime', sqlalchemy.Time, default=datetime.now().time())
)
These lines will create an object address_table which has definitions of each column and will be used to create table in database.
Map Your Table To Python Class
Create a python class
- Now we map the database table to a python class.
- This basically means that our database will become a python class. We will be able to call its attributes and use it just like you would use normal classes and functions in python.
- Create an empty python class which will hold our data later. Capitalize the first character.
#Object Creation
#This is an empty class that will become our data class
class Addressbook(object):
pass
Map python class
- Now map the empty class to database object.
#Mapping of Table to Object addresstable_mapper=mapper(Addressbook,address_table)
- This actually connects the database table definition you created and empty python class.
Now Addressbook knows about each column and you can referance it as Addressbook.City for example.
- It also knows what type it is and how to retrieve, insert, delete that record.
- Save and Exit.
Note: Sqlalchemy 0.3, assign_mapper has been depreciated and default is to use a mapper. If you are looking for assign_mapper functionality take a look at Elixir Project.
Create Tables in Database
- Final step, and the easiest one.
- Create database by issuing command :
tg-admin sql create
If you experience problems or errors go back to installation and make sure you have all the components. If that doesn't fix the error check your model.py
TurboGears Flow
- Controller.py hold all your data transformations. Passing data from one thing to another, and converting it on the way there is done here.
- Since we defined the data structure in our model we can now use it to query database.
- We will pass the results to a kid template that will display the data for us. template.addresses will do just that.
- To create a list of addresses add this to controlls.py
@expose(template="myfirstproject.templates.addresses")
def addresses(self):
from model import Addressbook
x=Addressbook.select()
return dict(addresses=x)
- @expose(template="myfirstproject.templates.addresses") -- tells which template to pass the results of a function
- def addresses(self): -- tells what the URL for the function be. localhost:8080/addresses
- return dict(addresses=x) --tells what to return. addresses.kid will have addresses object available to it to display.
Template
templates/address.kid is where all your data is displayed as xhtml. You tell it how to display it by modifying the template.
- Copy the welcome.kid to addresses.kid and replace everything in body tag with:
<body>
<ul>
<li py:for="record in addresses">
<a py:content="record.FirstName">first name</a>
<a py:content="record.LastName">last name</a>
</li>
</ul>
</body>
- [addresses is available to the template because the function addresses in controls.py return it.]
Visit: http://localhost:8080/addresses
We now finished with displaying addresses. Now its time to create a form so we can insert them.
Save Form
- First we create a controller that will save our address book.
- Make these changes in controlls.py
- On top line where you see:
from turbogears import controllers, expose
add redirect at the end of list.
from turbogears import controllers, expose, redirect
- Then below root class add this function
@expose()
def saveaddressbook(self,first_name,last_name):
from model import AddressBook
first_name=first_name
last_name=last_name
AddressBook(first_name=first_name,last_name=last_name)
raise redirect("/addresses")
This function expects the first and last name to be passed into it.You can reach this function at localhost:8080/saveaddressbook but it will give you an error if you don't pass first and last name. It will save names using the Addressbook Class from the model. At the end it will redirect to localhost:8080/addresses
Edit form
- Now let's create actual form to input the names:
- First we need a controller, so add this into your controllers.py
@expose(template="myfirstproject.templates.form")
def addressbookform(self):
return dict()
- This will sent empty dictionary to template form, and will allow you to access localhost:8080/addressbookform
- Now inside templates lets' create form.kid
- Copy welcome.kid to form.kid and replace the whole body with this:
<body> <form NAME="Add Addressbook" METHOD="post" ACTION="/saveaddressbook"> <p>First Name: <input name="first_name"></input></p> <p>Last Name: <input name="last_name"></input></p> <p><input type="submit" value="submit"></input></p> </form> </body>
Now we are done. go to http://localhost:8080/addressbookform and you should see your form.
After you submit it you should be redirected to http://localhost:8080/addresses
- If you experienced an error :
ExpatError: mismatched tag: line 13, column 2
- You need to check your form.kid because it expects valid xhtml code. This error means that your template has some kind of xhtml syntax error.
TurboGears in Second(II) Gear
- This should make your realize how fast and easy you can create your turbogears app, or how easy you can extend your desktop application.
- Extend your existing application to web
- Use existing database
- Create forms
- Validate forms
- Create proccess
- Save data
- Verify data
- Confirm final submition
TurboGears Forms
Widgets and Validators
- Widget is a collection of tools to build html forms automatically for you. Validators is a collection of tools to validate the input from the html form automaticly.
We start from a beginning with tg-admin quickstart, our app will be called addressbook
Form Widget
- In your controller.py add these 4 modules to the import list, widgets, validators, error_handle, validate
- Your line should look similar to this.
from turbogears import controllers, expose, widgets, validators, error_handler, validate
- Above root class, lets create class with our form fields.
- This class is what defines the each part of a html form and what needs to be validated when the form is filled.
Label will be displayed next to the field. By default it is what the field name you gave it ex. firstname. If you want it to be changed the displayed name you add label="First Name" inside with the rest of the parameters.
With validators such as money, number,etc empty fields will be still accepted. If you would like to force the field to not be empty you have to add(not_empty=True) to your definition. Look at syntax of yourcarvalue below.
If you would like to use multiple validators you would use: validators.all(validators.plaintext(),validators.minLength(15))
- Here are some sample fields and validators just to get you started. See the full list for all available widgets.
class AddressBookFields(widgets.WidgetsList):
firstname = widgets.TextField(validator=validators.NotEmpty)
description = widgets.TextArea(validator=validators.NotEmpty)
homepage = widgets.TextField(validator=validators.URL)
yourcarvalue = widgets.TextField(label="Car Value", validator=validators.Money(not_empty=True))
zipcode = widgets.TextField(label="ZipCode",validator=validators.PostalCode)
- Now that you created your widget we will have to initiate it. We initiate it right below the class, otherwise instate it where you need it. We will reference our form by this name, address_form.
addressbook_form = widgets.TableForm(fields=AddressBookFields(),submit_text="save address")
You are done with html form, html form validation aka. widget.
Below you will find an example of choices you can make when creating widget:
class BigAddressBookFields(widgets.WidgetsList):
firstname = widgets.TextField(validator=validators.NotEmpty)
description = widgets.TextArea(validator=validators.NotEmpty)
homepage = widgets.TextField(validator=validators.URL)
yourcarvalue = widgets.TextField(label="Car Value", validator=validators.Money(not_empty=True))
zipcode = widgets.TextField(label="ZipCode",validator=validators.PostalCode)
age = widgets.TextField(label="Your Age",validator=validators.Int)
sex = widgets.SingleSelectField(label="Gender",validator=validators.NotEmpty, options=['Female','Male'])
maritalstatus = widgets.SingleSelectField(label="Marital Status", validator=validators.NotEmpty,options=['Single','Married'])
dob = widgets.CalendarDatePicker(format = '%Y/%m/%d',validator = validators.DateTimeConverter(format="%Y/%m/%d"))
year=widgets.TextField(attrs={'size':4,'maxlength':4},validator=validators.All(validators.Number(not_empty='True'),validators.MinLength(4)))
searchin = widgets.RadioButtonList(label="Search in",validator=validators.NotEmpty,options=['Option1','Option2'])
searchfor = widgets.RadioButtonList(label="Search For",validator=validators.NotEmpty,options=['Option1','Option2'],default='Option1')
searchtype = widgets.RadioButtonList(label="Search Type",validator=validators.NotEmpty, options=[(1,'Exact'),(2,'Slow')],default=1)
- You can type widgets in a following format if it makes it easier to read for you:
myfield = widgets.TextField(
name='title', label='Title',
attrs={'size': 64, 'maxlength': 64},
validator=v.All(validators.NotEmpty, validators.UnicodeString)
)
Page URL
- Lets define a url where our form will be accessible from the internet.
- Again in controller.py Under a root class add this:
@expose(template="addressbook.templates.form")
def addressbook(self):
submit_action = "/addressbookprocess"
return dict(form=addressbook_form,action=submit_action)
- First line tells you which template will be used.
Second line tells you what will be the url of this method. http://localhost:8080/addressbook
- Submit action tells where should the form input be sent.
- Last line returns a dictionary 'form', which is equal to addressbook_form, and we pass an action as well.
Page template
- Now let's create a form.kid in the template folder
- In Template folder copy welcome.kid and create form.kid
Replace the <body\> with this:
<body>
${form(action=action)}
</body>
Validate the widget/form
- Our form will be submited to /addressbookprocess. In controller.py we need to create that url. Again Under a root class add this function.
@expose()
@error_handler(addressbook)
@validate(form=addressbook_form)
def addressbookprocess(self,**kwargs):
return dict(kwargs=kwargs)
- Error handler will catch the error and if one exists it will pass it back to where it came from. In our case addressbook.
- Validate will validate the form.
- Addressbookprocess will process the form. We will save the content later, for now we pass values to our function via **kwargs (key word arguments)
FYI. *name syntax gets all the parameters and puts them in list. You can reference the list as *name[0] for first argument, etc.
Now if you wanted to save your addressbook follow the same proccess that we discussed in previus example. Look at the Database model paragraph and save forma paragraph.
If you are building a registration forms you might want to try:Registration for TG. It is a set of tools to help you register users.
More on Validate Widget
- Make sure your controller now imports proper modules from turbogears
from turbogears import redirect, widgets,validators, error_handler, validate,flash
- Define your widget definition class and create object you will call later
class AddressBookFields(widgets.WidgetsList):
firstname = widgets.TextField(validator=validators.NotEmpty)
description = widgets.TextArea(validator=validators.NotEmpty)
homepage = widgets.TextField(validator=validators.URL)
# Create object and set submit button text
address_form = widgets.TableForm(fields=AddressBookFields(),submit_text="save address")
- Create controller function for your widget
@expose(template="addressbook.templates.addressupdate")
def addressupdate(self):
submit_action = "/addresssave"
return dict(form=address_form,action=submit_action)
- Add widget form to the template
<html>
<body>
<p> ${form(action=action)} </p>
</body>
</html>
- Handle error, validate and proccess, and inform about results from the widget
#@expose(template="addressbook.templates.addresssave")
@expose()
@error_handler(addressupdate)
@validate(form=address_form)
def addresssave(self,**kwargs):
flash('Addressbook Information are Saved')
#You can save the information stored in dictionary kwargs to your database, proccess data, etc
# return dict(kwargs=kwargs) or raise redirect("/index") or return other information.
return dict(kwargs=kwargs)
Pre-fill Widgets
- You can pre-fill widgets by returning the values they should have.
- I am querying the database using sqlalchemy:
d=model.Useraddress() x=d.get_by(USER_SID=345,ADDRESS_SID=2)
Then I pass x(the corresponding record) to my template
return dict(address=address_form,value=x, action=submit_action)
- In my template I add the (value=value) option.
<p><span>${address(value=value, action=action)}</span></p>
- Done. You widget is prefilled.
Widgets options
- To find options for widgets. Start python, and type
import turbogears
- Now type
dir(turbogears.widgets)
- You will get a list of available functions.You should see.
['AjaxGrid', 'AutoCompleteField', 'Button', 'CSSLink', 'CSSSource', 'CalendarDat ePicker', 'CalendarDateTimePicker', 'CalendarLangFileLink', 'CheckBox', 'CheckBo xList', 'CompoundFormField', 'CompoundInputWidget', 'CompoundWidget', 'DataGrid' , 'FieldSet', 'FileField', 'Form', 'FormField', 'FormFieldsContainer', 'HiddenFi eld', 'ImageButton', 'InputWidget', 'JSLink', 'JSSource', 'JumpMenu', 'Label', ' Link', 'LinkRemoteFunction', 'ListForm', 'LocalizableJSLink', 'MultipleSelectFie ld', 'PaginateDataGrid', 'PasswordField', 'RPC', 'RadioButtonList', 'RemoteForm' , 'RepeatingFieldSet', 'RepeatingFormField', 'RepeatingInputWidget', 'ResetButto n', 'Resource', 'SelectionField', 'SingleSelectField', 'Source', 'SubmitButton', 'SyntaxHighlighter', 'Tabber', 'TableForm', 'TextArea', 'TextField', 'URLLink', 'Widget', 'WidgetDescription', 'WidgetsList', '__builtins__', '__doc__', '__fil e__', '__name__', '__path__', 'all_widgets', 'base', 'big_widgets', 'datagrid', 'forms', 'i18n', 'js_location', 'links', 'load_widgets', 'meta', 'mochikit', 're gister_static_directory', 'rpc', 'set_with_self', 'static']
This means you could for example work with datagrid. (http://www.checkandshare.com/blog/?p=24)
Validators options
- We follow similar step with validator. After opening python
import turbogears dir(turbogears.validators)
- You should see.
['All', 'Any', 'Bool', 'ConfirmType', 'Constant', 'CreditCardExpires', 'CreditCa rdSecurityCode', 'CreditCardValidator', 'DateConverter', 'DateTimeConverter', 'D ateValidator', 'DictConverter', 'Email', 'Empty', 'FancyValidator', 'FieldStorag eUploadConverter', 'FieldsMatch', 'FileUploadKeeper', 'ForEach', 'FormValidator' , 'IndexListConverter', 'Int', 'Invalid', 'JSONValidator', 'MaxLength', 'MinLeng th', 'Money', 'MultipleSelection', 'NoDefault', 'NotEmpty', 'Number', 'OneOf', ' PhoneNumber', 'PlainText', 'PostalCode', 'Regex', 'RequireIfMissing', 'RequireIf Present', 'Schema', 'Set', 'SignedString', 'StateProvince', 'String', 'StringBoo l', 'StringBoolean', 'StripField', 'TgFancyValidator', 'TimeConverter', 'URL', ' UnicodeString', 'Validator', 'Wrapper', '_', '__builtin__', '__builtins__', '__d oc__', '__file__', '__name__', '_findall', '_illegal_s', 'cgi', 'datetime', 'for mat', 'jsonify', 'pkg_resources', 're', 'simplejson', 'strftime_before1900', 'ti me', 'turbogears', 'util', 'validators', 'warnings']
Password validators
- This would mostly be used to see if the password in two fields are the same.
class PasswordFields(widgets.WidgetsDecalration):
passwd = widgets.PasswordField(validators=validators.NotEmpty())
passwd2 = widgets.PasswordField(validators=validators.UnicodeString())
class PasswordSchema(fromencode.schema.Schema):
chained_validators=[validators.FieldsMatch('passswd','passwd2')]
form = TableForm(fields=PasswordFields(), validator=PasswordSchema)
Focus cursor on the form field
You can read more on focusing on fields here
You need to change your <body> tag to:
<body onload="document.getElementById('myfield').focus()">
TurboGears dispaly Widgets
DataGrid
DataGrid allows you to display data in a grid like way.
DataGrid requires you to describe what you're going to display via passing a string as the field name or use callables to return what you want. The example with sqlalchemy shows displaying using field name, and second example shows using lambda callable function.
DataGrid's template is very simple.
DataGrid and SqlAlchemy Example
DataGrid displays our data in a Grid Like table. It calls attributes of a class like this: myclass.FirstName, myclass.LastName. You get this type of structure when you deal with sqlalchemy and mapper, so I assume you want to display some data from sqlachemy here.
We first need to create a data grid description. DataGrid will use it to display what we want in order we want.
from turbogears.widgets import DataGrid
myusers_datagrid = DataGrid(fields=[
('DisplayedColumnName1', 'LastName'),
('DisplayedColumnName2', 'FirstName'),
('DisplayedColumnName3', 'PhoneNumber'),
])
Each tuple ('DisplayedColumnName1', 'LastName'), defines single column in the table.
DisplayedColumnName1 parameter defines how your whole column will be called. The LastName is an attributes' name of the class you will be trying to get the data out of. Example: myclass.LastName.
- So now we need to pass a list of the data we want to display.
- Here we are doing Select, but you could select it somewhere else in a code and just pass the results to display function.
- We pass something iterable to display() function of our widget.
mydatagrid=myusers_datagrid.display(Users.select()) retrun dict(mydatagrid=mydatagrid)
- In your template just add this where you want to display your data:
<span py:content="mydatagrid">datagrid will appear here</span>
- You are done. Wasn't that easy?
Data Grid Example with static content
- Let say you want to display something on the bottom of your page in a datagrid like manner, and you don't need a database.
- Add this in your model.py file
from turbogears.widgets import DataGrid
- In Model.py we will add our data grid. For now we just need to display some semi-static data in a grid so we will handcode the data fields and some values.
mycustom_widget = DataGrid(fields=[
('NumberOfPayments', lambda row=row[0]),
('Due Each Month', lambda row=row[1]),
])
mydefaults=[(6,100),(2,300)]
- This initiates a datagrid instance that has 2 columns: numberofpayments and due each month.
We create a list of some numbers that we will passed into this instance. In order to retrive the values from the list we use lambda which acts like a anonymous function. If you are not familiar to lambda this is how it would look in normal python way: def somefunction(row): return row[0]
- In controller.py under your function you want to display the data add this:
from model import *
mydatagrid=mycustome_widget.display(mydefaults)
return dict(mydatagrid=mydatagrid)
- We pass our list of defaults to display() function of our widget.
- We now need to return mydatagrid to our template.
- Now in your template add this anywhere you want to display the data.:
<span py:content="mydatagrid">datagrid will appear here</span>
Paginate Data Grid
- With paginate datagrid you can divide query results into subsets for easier or more useful display via page1(50 results),page2(another 50 results),page3...etc.
You need to import paginate, so your import lines need to have paginate, and url from turbogears, and PaginateDataGrid from widget.
from turbogears import controllers, expose, flash,widgets, validators, error_handler, validate, paginate, url from turbogears.widgets import PaginateDataGrid
- You define paginate data grid just like you would datagrid but you add sortable option if you want.
#Create Sortable Option
sortable = dict(sortable=True)
mytable_grid = PaginateDataGrid(name='my big results',
fields=[
('ID', 'id', sortable),
('Groupname', 'group_name'),
('Last Name', 'last_name', sortable),
('Members', 'num_members', sortable)
])
- In your controller before expose you add a @paginate decorator, and you return a widget and data source separately.
@expose(template="myapp.templates.mybigpage")
@paginate('myresults',limit=50,default_order='last_name')
def mybigpage(self):
#do some query here myresults=.....
return dict(mytablegrid=mytable_grid,myresults=myresults)
*In your template add:
<p><span py:content="mytablegrid(myresults)">My Grid will show here.</span></p>
- You are done.
Fast Data Grid
FastDataGrid is sophisticated enough to figure out how to display an arbitrary results from a select statment instance that was done when you do .select() on you SQLObject's model object.
FastDataGrid is a seperate module for Turbogears and it needs to be downloaded from turbogears website.
sudo easy_install -f http://turbogears.org/download/ TGFastData
SqlAlchemy (SA)
- You can find full documentation on sqlalchemy at their website, but this section will get you up to speed.
If you need to use sqlalchemy on its own try this sqlalchemy tutorial
Start new TurboGears project with sqlalchemy.
tg-admin quickstart --sqlalchemy
Database Connection
- In dev.cfg you will be connecting to a database. Sqlalchemy allows you to create your own tables or use pre-existing tables.
- You will have to log into database and create user,password, and database. You can do it via mysql administrator program.
Setup the connection
- In dev.cfg we connect to our database.
sqlalchemy.dburi="mysql://username:password@localhost:3306/databasename
- If you need to connect to other database, pick one of these:
sqlalchemy.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" sqlalchemy.dburi="mysql://username:password@hostname:3306/databasename" sqlalchemy.dburi="postgres://username:password@hostname/databasename sqlalchemy.dburi="oracle://username:password@hostname:1521/sidname"
For mssql on Linux, using pyodbc and unixODBC
sqlalchemy.dburi="mssql://username:password@hostname:1433/databasename?driver=TDS&odbc_options='TDS_Version=8.0'"
You don't have to provide the port as sqlalchemy knows default ports.
What needs to be imported
Modify the import lines in model.py so that they look like:
from turbogears.database import metadata, session, bind_meta_data from sqlalchemy.ext.assignmapper import assign_mapper import sqlalchemy
bind to database
- Now bind the connection to your database in model.py. This function will bind to the connection you have setup at dev.conf
bind_meta_data()
create tables
Load Existing Table
- Create an instance for your first table.
Add this to your model.py file. Replace yourtablename with the actual table name from your database.
#Creating table sctructure from our database.
yourtablename_table = sqlalchemy.Table('yourtablename', metadata, autoload=True)
- Above line will create object yourtablename_table which will know and store definitions of the table.
Create your own table
- If you are starting a new project and you want to create a table here is a sample table you can use.
- You do it again in model.py. Add something similar to this one class.
address_table = sqlalchemy.Table('address', metadata,
sqlalchemy.Column('Address_Sid', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('FirstName', sqlalchemy.Unicode(40),nullable=False),
sqlalchemy.Column('LastName', sqlalchemy.Unicode(40),nullable=False),
sqlalchemy.Column('MaidenLastName', sqlalchemy.Unicode(40)),
sqlalchemy.Column('Email', sqlalchemy.Unicode(80),nullable=False),
sqlalchemy.Column('Address', sqlalchemy.Unicode(80),nullable=False),
sqlalchemy.Column('City', sqlalchemy.Unicode(80),nullable=False),
sqlalchemy.Column('State', sqlalchemy.String(2),nullable=False),
sqlalchemy.Column('ZipCode', sqlalchemy.Integer,nullable=False),
sqlalchemy.Column('DOB', sqlalchemy.Date(),nullable=False),
sqlalchemy.Column('CreatedDate', sqlalchemy.Date, default=datetime.now().date()),
sqlalchemy.Column('CreatedTime', sqlalchemy.Time, default=datetime.now().time())
)
- Save and exit. Now that model.py has its first table you will have to create it in our database.
- To create actual database in issue this command.
tg-admin sql create
SqlAlchemy: Database tables are classes, rows are instances, fields are attributes
You can always refere to sqlalchemy types documentation to get a full list of available options.
- Here is a sample:
Captialized refers to a SQL standard type, whereas non-capitalized is a "generic" type that may resolve differently on different database backends.
module sqlalchemy.types
* class BLOB(Binary)
* class BOOLEAN(Boolean)
* class Binary(TypeEngine)
* class Boolean(TypeEngine)
* class CHAR(String)
* class CLOB(TEXT)
* class DATE(Date)
* class DATETIME(DateTime)
* class DECIMAL(Numeric)
* class Date(TypeEngine)
* class DateTime(TypeEngine)
* class FLOAT(Float)
* class Float(Numeric)
* class INT(Integer)
* class Integer(TypeEngine)
* class Interval(TypeDecorator)
* class NCHAR(Unicode)
* class NUMERIC(Numeric)
* class Numeric(TypeEngine)
* class PickleType(MutableType,TypeDecorator)
* class SMALLINT(SmallInteger)
* class SmallInteger(Integer)
* class String(Concatenable,TypeEngine)
* class TEXT(String)
* class TIME(Time)
* class TIMESTAMP(DateTime)
* class Time(TypeEngine)
* class TypeDecorator(AbstractType)
* class TypeEngine(AbstractType)
* class Unicode(String)
* class VARCHAR(String)
create python data class
- Now we map the database table to a python class that we will use to manipulate our data.This basically means that our database will become a python class that we can call its attributes etc.
- Create an empty python class which will hold our data later. Capitalize the first character.
- Add this to model.py
#Object Creation
#This is an empty class that will become our data class
class Yourtablename(object):
pass
map database to python class
- Map the empty class to database object.This actually connects the database to our class that we just created. It tells the class what fields, attributes, functions it allows.
#Mapping of Table to Object yourtablename_mapper=assign_mapper(session.context,Yourtablename,yourtablename_table)
- You are done with model.py
Your final model.py should look something like this. In this case I am using table called binder
from turbogears.database import metadata, session,bind_meta_data
from sqlalchemy.ext.assignmapper import assign_mapper
import sqlalchemy
#Binding sqlalchemy to a turbogears database
bind_meta_data()
#[Mysql option]Fixed in next relese. Table creation, ticket 482
#from turbogears import database
#engine=database.get_engine()
#tables = []
#for name in engine.execute("SHOW TABLES"):
# tables[name] = sqlalchemy.Table(name, metadata, autoload=True)
#Using manual table creation
binder_table = sqlalchemy.Table('binder', metadata, autoload=True)
bdriver_table = sqlalchemy.Table('bdriver', metadata, autoload=True)
bcoverage_table = sqlalchemy.Table('bcoverage', metadata, autoload=True)
bvehicle_table = sqlalchemy.Table('bvehicle', metadata, autoload=True)
bviolation_table = sqlalchemy.Table('bviolation', metadata, autoload=True)
bdiscschg_table = sqlalchemy.Table('bdiscschg', metadata, autoload=True)
#Object Creation
#This is an empty class that will become our data class
class Binder(object):
pass
class bdriver(object):
pass
class bcoverage(object):
pass
class bvehicle(object):
pass
class bviolation(object):
pass
class bdiscschg(object):
pass
#Mapping of Table to Object
bindermapper=assign_mapper(session.context,Binder,binder_table)
bdrivermapper=assign_mapper(session.context,bdriver,bdriver_table)
bvehiclemapper=assign_mapper(session.context,bvehicle,bvehicle_table)
bcoveragemapper=assign_mapper(session.context,bcoverage,bcoverage_table)
bviolationmapper=assign_mapper(session.context,bviolation,bviolation_table)
bdiscschmapper=assign_mapper(session.context,bdiscschg,bdiscschg_table)
When Done Don't forget to run this command in root directory of the project.
tg-admin sql create
create table in sqlalchemy
datatypes
Here are sqlalchemy data types: Sqlalchemy Data Types
- Example Sqlalchemy Table
address_table = sqlalchemy.Table('address', metadata,
sqlalchemy.Column('Address_Sid', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('FirstName', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('LastName', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('MaidenLastName', sqlalchemy.Unicode(128)),
sqlalchemy.Column('Email', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('Address', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('City', sqlalchemy.Unicode(128),nullable=False),
sqlalchemy.Column('State', sqlalchemy.String(2),nullable=False),
sqlalchemy.Column('ZipCode', sqlalchemy.Integer,nullable=False),
sqlalchemy.Column('DOB', sqlalchemy.Date(),nullable=False),
sqlalchemy.Column('CreatedDate', sqlalchemy.Date, default=datetime.now().date()),
sqlalchemy.Column('CreatedTime', sqlalchemy.Time, default=datetime.now().time())
)
autoload
Primary, auto increment, unique, alternative, composite keys
unique
# per-column anonymous unique constraint
Column('col1', Integer, unique=True),
Column('col2', Integer),
Column('col3', Integer),
# explicit/composite unique constraint. 'name' is optional.
UniqueConstraint('col2', 'col3', name='uix_1')
controller.py, Data passing and conversion
In controller you you to add this to import lines if they don't have it included:
from quote import model
Direct Sql statements to a database
- You can use direct sql statements to get the data you need.
from turbogears import database
engine=database.get_engine()
engine.execute("SHOW TABLES"):
Basic select()
There are two ways you can get data from database via sqlaclhemy, via Query or via Select. The "Query class should not be confused with the Select class, which defines database SELECT operations at the SQL (non-ORM) level. Query differs from Select in that it returns ORM-mapped objects and interacts with an ORM session, whereas the Select construct interacts directly with the database to return iterable result sets."10
- The simplest form of select is:
s=Users.select()
Here we select all from that table. aka select * from Users
equal, not equal, less then, more then
- To select partucular record
s1=Users.select(Users.c.LASTNAME=='Smith')
more or less
- Less or More
s1=Users.select(Users.c.AGE < 40)
and ,or ,not
- Use two fields And or or
s1=Users.select((Users.c.LASTNAME=='Smith') & (Users.c.FIRSTNAME=='John')) s1=Users.select((Users.c.LASTNAME=='Smith') | (Users.c.FIRSTNAME=='John'))
- Or you want to select everybody except for Smith
s1=Users.select( ~(Users.c.LASTNAME=='Smith'))
As you can see we are using a Users.select() function to get these values. As a parameter we are giving a combinations of Users.c.FIELDNAME
like, endswith, startswith, between, in
- You can also use other ways to find your results, but this time we will use a build in functions on that FIELDNAME that we are using.(s1=Users.select(Users.c.FIELDNAME.SOMEFUNCTION) These include:
s1=Users.select(Users.c.AGE.between(18,21))
s1=Users.select(Users.c.LASTNAME.like('%a'))
s1=Users.select(Users.c.FaxNumber.like('%'+str(kwargs['FaxNumber'])+'%'))
s1=Users.select(Users.c.LASTNAME.endswith('th'))
s1=Users.select(Users.c.LASTNAME.startswith('Mr'))
s1=Users.select(Users.c.LASTNAME.in_('Smith','Johnson'))
- As you saw we used functions: like, endswith, startswith, between, in_ functions there are few more but you have to see for yourself how they work.
- More like examples:
s1=Users.select(Users.c.LASTNAME.like('%'+kwargs['LASTNAME']+'%'))
s1=Users.select(Users.c.LASTNAME.like('%'+str(kwargs['USERID'])+'%'))
Advenced select()
different select: sqlalchemy.select()
- Now that you have a handle on this select() function. There is another select function that is part of sqlalchemy, but that function needs to be executed.
import sqlalchemy s2=sqlalchemy.select(Users.c.LASTNAME=='Smith') s3=s2.execute()
The actual going to a database happens when you issue a execute()
- If you don't want to select all fields you can tell select which fields you want. sqlalchemy.select().execute()
s1=sqlalchemy.select( [Users.c.LAST,Users.c.FIRST,Users.c.Age],(Users.c.LASTNAME=='Smith')).execute()
group_by
- With this select you are able to group single fields and do a group by queries.
- To select a single column you do:
x=sqlalchemy.select([Users.c.AGE], Users.c.LASTNAME=='Smith') x2=x.execute()
- To Select a single column and group it by some column you do:
x2=sqlalchemy.select([Users.c.AGE], group_by=[Users.c.AGE]) x2=x.execute()
- If you want to combine where and group by you do:
x2=sqlalchemy.select([Users.c.AGE], Users.c.LASTNAME=='Smith',group_by=[Users.c.AGE]) x2=x.execute()