del.icio.us,Dig IT

Download this page in : in pdf, in OpenOffice odt file

I want to help this page

This page is starting to be fazed out to Turbogerars2. If you are starting to learn turbogears we recomend that you start with turbogears2. see TurboGears2

Contents

  1. Start Here
    1. Short Intro To TurboGears
    2. Search TG docs
  2. Install TurboGears
  3. QuickStart a new project
    1. Create project
    2. Start the project
    3. Make changes
  4. Turbogears Overview
    1. Add,remove URL in controller.py
    2. Database settings
    3. Database tables using model.py
    4. Kid template
  5. First webapp: Address Book
    1. Database Model
      1. Import Proper Modules
      2. Create Tables
      3. Map Your Table To Python Class
      4. Create Tables in Database
    2. TurboGears Flow
      1. Template
      2. Save Form
      3. Edit form
  6. TurboGears in Second(II) Gear
    1. TurboGears Forms
      1. Widgets and Validators
      2. Form Widget
      3. Page URL
      4. Page template
      5. Validate the widget/form
      6. More on Validate Widget
      7. Pre-fill Widgets
      8. Widgets options
      9. Validators options
      10. Password validators
      11. Focus cursor on the form field
    2. TurboGears dispaly Widgets
      1. DataGrid
      2. DataGrid and SqlAlchemy Example
      3. Data Grid Example with static content
      4. Paginate Data Grid
      5. Fast Data Grid
  7. SqlAlchemy (SA)
    1. Database Connection
      1. What needs to be imported
      2. bind to database
      3. create tables
      4. create python data class
      5. map database to python class
    2. create table in sqlalchemy
      1. datatypes
      2. autoload
      3. Primary, auto increment, unique, alternative, composite keys
    3. controller.py, Data passing and conversion
    4. Direct Sql statements to a database
    5. Basic select()
      1. equal, not equal, less then, more then
      2. more or less
      3. and ,or ,not
      4. like, endswith, startswith, between, in
    6. Advenced select()
      1. different select: sqlalchemy.select()
      2. group_by
      3. select_by
    7. available functions of sqlalchemy
      1. properties of python class and sql
      2. properties of a field name
      3. list of available fields, proprties
      4. working with columns
      5. Select() function properties
      6. get() function
    8. insert record
    9. update record
      1. Dispaly record
    10. Flow Control: update,submit,save,display
    11. Saving table with many columns
    12. Saving multiple records
    13. sqlalchemy in virtualenv
  8. Session Managment
    1. Session ID
  9. Install Turbogears with Apache
    1. apache and mod_wsgi
      1. Install mod_wsgi
      2. Configure your Turbogears app for mod_wsgi
      3. Turbogears and modwsgi in VirtualHost,virtualenv, and subdomain
      4. Enable your website
      5. advence mod_wsgi memory management
      6. Stress test your app
    2. Egg deploy
      1. Create an Egg File
      2. dev.cfg app.cfg prod.cfg
      3. Deploy an EGG file
      4. Configure TurboGears prod.cfg
      5. Run the app
    3. Mod_Proxy
      1. Enable mod proxy
      2. Configure apache
      3. Auto start of the app
      4. Server Log
    4. Troubleshooting Deployment
    5. mod_python
      1. Install project file
      2. Test project file
      3. Configure apache2 with your turbogears project
      4. Error
  10. Turbogears API Details
    1. Packages
    2. Modules
    3. Classes
  11. Performance
    1. Genshi vs other
    2. maco vs Cheetah
    3. Sqlalchemy vs storm
  12. Errors
    1. TgFastData for python 2.5
  13. EXTRA
    1. Produce PDF Pages
    2. MyTube with Flex and Turbogears
    3. captcha widgets for a form
    4. Basic Way to display column data from a database
    5. Identity Management
    6. TurboGears with existing MySQL database
    7. Flash status Bar
    8. Tagging with Turbogears
    9. Drag and Drop Sort list
    10. Turbogears and Oracle
    11. Turbogears memory managment
    12. unixODBC
    13. Authenticating against an external password source
    14. Embed swf files in your turbogears code (IE, Opera, Firefox etc)
    15. SQLObject (SO) quick Overview
      1. dev.conf -database connection
      2. model.py -database model
      3. sqlobject features
      4. SQLObject save to database
  14. Turbogears Specifics usage
    1. Use CAPITAL names in widgets and sqlalchemy autoload
    2. redirect all requests to index
  15. Other Documentation
    1. IBM
    2. ORACLE
  16. Common Errors
    1. non-keyword arg after keyword arg
    2. cherrypy._cperror.NotReady: Port not free
    3. ExpatError: not well-formed (invalid token)
    4. Could not assemble any primary key columns for mapped table
Original Document is located here: http://lucasmanual.com/mywiki/TurboGears

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.

  1. Please start from the beginning of this page if you are new to TurboGears.

  2. If you are looking for something specific please go over the menu items.

  3. 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.

  1. Turbogears.
  2. 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.

aptitude update
aptitude install python-turbogears

aptitude install sqlite3
aptitude install python-pysqlite2

aptitude install mysql-server
aptitude install python-mysqldb

You are ready to start your turbogears development.

QuickStart a new project

Create project

tg-admin quickstart --sqlalchemy

Enter project name: myfirstproject
Enter package name [myfirstproject]

Start the project

python start-myfirstproject.py

Make changes

Just go into your project folder, inside there should be:

  1. dev.cfg - where you set configuration properties for your project.
  2. setup.py - which you can use to install your python project into python site-package
  3. myfirstproject folder - There is a folder with a same name as your project, inside there are:
    1. templates - which hold all your html templates (welcome.kid)
    2. static - which holds your images, css, and javascript
    3. config- where you will find your app specific configuration.
    4. model.py - which has your data models
    5. 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

    @expose(template="myfirstproject.templates.welcome")
    def index(self):
        import time
        # log.debug("Happy TurboGears Controller Responding For Duty")
        return dict(now=time.ctime())

    @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

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

from sqlalchemy import *
to
import sqlalchemy

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())
    )

tg-admin sql create

Kid template

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

<?python
myvariable = 'i want this text to replace the variable name in template'
?>
<span py:content="myvariable">Text to be replaced</span>

<div py:content="document('header.html')">Replace this text</div>

<meta content="text/html";charset=UTF-8" http-equiv="content-type" py:replace="''"/>

<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>

 <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

tg-admin quickstart --sqlalchemy

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.

Database Model

Before we start lets make sure you have all modules imported and you know what is for what.

  1. Make sure you imported proper modules.
  2. Define your tables. 1.Create and bind your database to python class.

Import Proper Modules

  1. 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

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())
    )

Map Your Table To Python Class

Create a python class

#Object Creation
#This is an empty class that will become our data class
class Addressbook(object):
    pass

Map python class

#Mapping of Table to Object
addresstable_mapper=mapper(Addressbook,address_table)

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

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

    @expose(template="myfirstproject.templates.addresses")
    def addresses(self):
        from model import Addressbook
        x=Addressbook.select()
        return dict(addresses=x)

Template

<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>

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

from turbogears import controllers, expose

add redirect at the end of list.

from turbogears import controllers, expose, redirect

    @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

    @expose(template="myfirstproject.templates.form")
    def addressbookform(self):
        return dict()

<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>

ExpatError: mismatched tag: line 13, column 2

TurboGears in Second(II) Gear

TurboGears Forms

Widgets and Validators

Form Widget

from turbogears import controllers, expose, widgets, validators, error_handler, validate

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)

addressbook_form = widgets.TableForm(fields=AddressBookFields(),submit_text="save address")

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)

myfield = widgets.TextField(
name='title', label='Title',
attrs={'size': 64, 'maxlength': 64},
validator=v.All(validators.NotEmpty, validators.UnicodeString)
)

Page URL

    @expose(template="addressbook.templates.form")
    def addressbook(self):
        submit_action = "/addressbookprocess"
        return dict(form=addressbook_form,action=submit_action)
  1. First line tells you which template will be used.
  2. Second line tells you what will be the url of this method. http://localhost:8080/addressbook

  3. Submit action tells where should the form input be sent.
  4. Last line returns a dictionary 'form', which is equal to addressbook_form, and we pass an action as well.

Page template

<body>
${form(action=action)}
</body>

Validate the widget/form

    @expose()
    @error_handler(addressbook)
    @validate(form=addressbook_form)
    def addressbookprocess(self,**kwargs):
        return dict(kwargs=kwargs)

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

from turbogears import redirect, widgets,validators, error_handler, validate,flash

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")

 @expose(template="addressbook.templates.addressupdate")
    def addressupdate(self):
        submit_action = "/addresssave"
        return dict(form=address_form,action=submit_action)

<html>
<body>
<p> ${form(action=action)} </p>
</body>
</html>

    #@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

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)

 <p><span>${address(value=value, action=action)}</span></p>

Widgets options

import turbogears

dir(turbogears.widgets)

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

Validators options

import turbogears
dir(turbogears.validators)

['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

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

<body onload="document.getElementById('myfield').focus()">

TurboGears dispaly Widgets

DataGrid

DataGrid and SqlAlchemy Example

from turbogears.widgets import DataGrid

myusers_datagrid = DataGrid(fields=[
    ('DisplayedColumnName1', 'LastName'),
    ('DisplayedColumnName2', 'FirstName'),
    ('DisplayedColumnName3', 'PhoneNumber'),
    ])

mydatagrid=myusers_datagrid.display(Users.select())
retrun dict(mydatagrid=mydatagrid)

<span py:content="mydatagrid">datagrid will appear here</span>

Data Grid Example with static content

from turbogears.widgets import DataGrid

mycustom_widget = DataGrid(fields=[
    ('NumberOfPayments', lambda row=row[0]),
    ('Due Each Month', lambda row=row[1]),
])

mydefaults=[(6,100),(2,300)]

        from model import *
        mydatagrid=mycustome_widget.display(mydefaults)
        return dict(mydatagrid=mydatagrid)

<span py:content="mydatagrid">datagrid will appear here</span>

Paginate Data Grid

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

#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)
])

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

Fast Data Grid

sudo easy_install -f http://turbogears.org/download/ TGFastData

SqlAlchemy (SA)

tg-admin quickstart --sqlalchemy

Database Connection

Setup the connection

sqlalchemy.dburi="mysql://username:password@localhost:3306/databasename

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&odbc_options='TDS_Version=8.0'"

You don't have to provide the port as sqlalchemy knows default ports.

What needs to be imported

from turbogears.database import metadata, session, bind_meta_data
from sqlalchemy.ext.assignmapper import assign_mapper
import sqlalchemy

bind to database

bind_meta_data()

create tables

Load Existing Table

#Creating table sctructure from our database.
yourtablename_table = sqlalchemy.Table('yourtablename', metadata, autoload=True)

Create your own table

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())
    )

tg-admin sql create

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

#Object Creation
#This is an empty class that will become our data class
class Yourtablename(object):
    pass

map database to python class

#Mapping of Table to Object
yourtablename_mapper=assign_mapper(session.context,Yourtablename,yourtablename_table)

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

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

from turbogears import database
engine=database.get_engine()
engine.execute("SHOW TABLES"):

Basic select()

s=Users.select()

equal, not equal, less then, more then

s1=Users.select(Users.c.LASTNAME=='Smith')

more or less

s1=Users.select(Users.c.AGE < 40)

and ,or ,not

s1=Users.select((Users.c.LASTNAME=='Smith') & (Users.c.FIRSTNAME=='John'))
s1=Users.select((Users.c.LASTNAME=='Smith') | (Users.c.FIRSTNAME=='John'))

s1=Users.select( ~(Users.c.LASTNAME=='Smith'))

like, endswith, startswith, between, in

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

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()

import sqlalchemy
s2=sqlalchemy.select(Users.c.LASTNAME=='Smith')
s3=s2.execute()

s1=sqlalchemy.select( [Users.c.LAST,Users.c.FIRST,Users.c.Age],(Users.c.LASTNAME=='Smith')).execute()

group_by

x=sqlalchemy.select([Users.c.AGE], Users.c.LASTNAME=='Smith')
x2=x.execute()

x2=sqlalchemy.select([Users.c.AGE], group_by=[Users.c.AGE])
x2=x.execute()

x2=sqlalchemy.select([Users.c.AGE], Users.c.LASTNAME=='Smith',group_by=[Users.c.AGE])
x2=x.execute()

select_by

User.select_by(User_sid=100, last_name='Smith')

available functions of sqlalchemy

properties of python class and sql

dir(User)
['IDCOLUMN', 'COLUMN1', 'WHATEVER','THE','COLUMN','NAME','IS','IN','THE','DATABASE',
 '__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', '_state',
 'c', 'count', 'count_by', 'delete', 'expire', 'expunge', 'flush', 'get', 'get_by', 'join_to', 'join_via', 'mapper', 'merge', 'refresh', 'save', 'save_or_update', 'select', 'select_by', 'selectone', 'update']

properties of a field name

>>> dir(Users.c.LASTNAME)
['_ColumnClause__label', '_ColumnElement__orig_set', '_Column__originating_column', '_SchemaItem__case_sensitive', '__add__', '__and__', '__class__', '__delattr__', '__dict__', '__div__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__invert__', '__le__', '__lt__', '__mod__', '__module__', '__mul__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__sub__', '__truediv__', '__weakref__', '_bind_param', '_case_sens', '_case_sensitive_setting', '_check_literal', '_compare', '_compare_self', '_compare_type', '_derived_metadata', '_determine_case_sensitive', '_find_engine', '_foreign_keys', '_get_case_sensitive', '_get_engine', '_get_from_objects', '_get_label', '_get_orig_set', '_get_parent', '_group_parenthesized', '_init_items', '_is_oid', '_label', '_make_proxy', '_negate', '_one_fkey', '_operate', '_primary_key', '_process_from_dict', '_selectable', '_set_casing_strategy', '_set_orig_set', '_set_parent', 'accept_schema_visitor', 'accept_visitor', 'append_foreign_key', 'args', 'autoincrement', 'between', 'case_sensitive', 'columns', 'compare', 'compile', 'constraints', 'copy', 'copy_container', 'default', 'distinct', 'endswith', 'engine', 'execute', 'foreign_key', 'foreign_keys', 'get_engine', 'in_', 'index', 'key', 'label', 'like', 'metadata', 'name', 'nullable', 'onupdate', 'op', 'orig_set', 'parens', 'primary_key', 'quote', 'scalar', 'select', 'shares_lineage', 'startswith', 'table', 'to_selectable', 'type', 'unique']

list of available fields, proprties

>>> print User.c.has_key('FIRSTNAME')
True
>>> print User.c.has_key('firstname')
False

>>> print User.c.FIRSTNAME
User.FIRSTNAME

 dir(User.c)
['_OrderedProperties__data', '__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__doc__', '__getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__len__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', '__weakref__', '_get_data', 'clear', 'get', 'has_key', 'keys']

working with columns

>>> dir(User.c.FIRSTNAME)
['_ColumnClause__label', '_ColumnElement__orig_set', '_Column__originating_column', '_SchemaItem__case_sensitive', '__add__', '__and__', '__class__', '__delattr__', '__dict__', '__div__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__invert__', '__le__', '__lt__', '__mod__', '__module__', '__mul__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__sub__', '__truediv__', '__weakref__', '_bind_param', '_case_sens', '_case_sensitive_setting', '_check_literal', '_compare', '_compare_self', '_compare_type', '_derived_metadata', '_determine_case_sensitive', '_find_engine', '_foreign_keys', '_get_case_sensitive', '_get_engine', '_get_from_objects', '_get_label', '_get_orig_set', '_get_parent', '_group_parenthesized', '_init_items', '_is_oid', '_label', '_make_proxy', '_negate', '_one_fkey', '_operate', '_primary_key', '_process_from_dict', '_selectable', '_set_casing_strategy', '_set_orig_set', '_set_parent', 'accept_schema_visitor', 'accept_visitor', 'append_foreign_key', 'args', 'autoincrement', 'between', 'case_sensitive', 'columns', 'compare', 'compile', 'constraints', 'copy', 'copy_container', 'default', 'distinct', 'endswith', 'engine', 'execute', 'foreign_key', 'foreign_keys', 'get_engine', 'in_', 'index', 'key', 'label', 'like', 'metadata', 'name', 'nullable', 'onupdate', 'op', 'orig_set', 'parens', 'primary_key', 'quote', 'scalar', 'select', 'shares_lineage', 'startswith', 'table', 'to_selectable', 'type', 'unique', 'use_labels']

Select() function properties

all=User.select()

all[0]    #To get the whole object
or
all[0].FIRSTNAME   #To get actual value
or
all[0].keys() #To get a list of all column names for that row
or
for column in all[0].c.keys():
  print getattr(all[0],column)

get() function

one=User.get(55)   #This will get all columns for primary key = 55
one_Lastname= User.get(55).LASTNAME   #This will just get one column for key = 55

one=User.get((55,3))   #This will get all columns for primary key1 = 55, key2=3

 *To Access the column with get you do similar thing as we did in example above.
{{{
one=User.get(55)
one.LASTNAME
one.FIRSTNAME
or
for column in one.c.keys():
    print getattr(one,column)

insert record

x=model.User()
x.LASTNAME='Smith'
x.FIRSTNAME='John'
x.AGE=29
x.save()
x.flush() #This will actually save it to a database

update record

y=Bdriver.get(343)
y.LASTNAME='Johns'
y.FIRSTNAME='Jimmy'
y.flush()

y=Bdriver.get((343,3))

Dispaly record

    @expose(template="quote.templates.all")
    def index(self):
        x=model.Binder.select()
        return dict(binders=x)

<div py:for="binder in binders">
    <span py:content="binder.BINDER_SID">bidner_sid</span>
    <span py:content="binder.LAST">last name </span>
    <span py:content="binder.FIRST">first name</span>
</div>

Flow Control: update,submit,save,display

class Root(controllers.RootController):
    @expose(template="quote.templates.welcome")
    def index(self):
        pass
    @expose(template="myapp.templates.updatepage1")
    def updatepage1(self):
        submit_action = "/savepage1"
        return dict(form=page1_form, action=submit_action)
    @expose()
    @error_handler(updatepage1)
    @validate(form=page1_form)
    def savepage1(self,**kwargs):
        .......
        #Move to next screen. Option 1 raise redirect
        flash('Policy Information Saved')
        raise turbogears.redirect(url("updatepage2",tg_errors=None))
        #option 2 Return function self.page2
        #return self.updatepage2()
    @expose(template="quote.templates.updatepage2")
    def upddriver(self,data=''):
        submit_action = "/savepage2"
        return dict(form=page2_form, action=submit_action)
    @expose()
    @error_handler(updatepage2)
    @validate(form=page2_form)
    def savedriver(self,**kwargs):
        .....
        #Redirect in a similar way as in savepage1

Saving table with many columns

tableinstance=model.Yourtable()
attribute=''
for key in kwargs.keys():
            attribute=upper(key)
            setattr(tableinstance,attribute,kwargs[key])
tableinstance.flush()

tableinstance=model.Yourtable() tableinstance.fieldname='some value' tableinstance.flush()

Saving multiple records

import sqlalchemy
#Binding sqlalchemy to a turbogears database
bind_meta_data()

#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
user_table = sqlalchemy.Table('User', metadata, autoload=True)
#Some other code that deals with assign mapper

    usertable=model.user_table.insert()
    recordstosave=[]
    #Do your for loop on a dictionary from a form widget
    for key,value in kwargs.items():
        new={}
        new['GROUP_SID']=primarysomevariable
        new['USER_SID']=somevalue
        #Defaults
        new['FACTOR']=0
        new['RATE']=0
        new['BASE']=0
        if key=='GROUP1' and value==True:
            new['group']=1
            recordstosave.append(new)
        elif key=='GROUP2' and value==True:
            new['group']=1
            recordstosave.append(new)
    usertabletable.execute(recordstosave)

sqlalchemy in virtualenv

aptitude install python-virtualenv
mkdir -p /usr/local/pythonenv
python /usr/lib/python2.4/site-packages/virtualenv.py /usr/local/pythonenv/BASELINE

Not Activated

export PYTHONPATH=/home/lucas/ENV/lib/python2.4/site-packages/
echo $PYTHONPATH

mkdir tmp
cd tmp
svn checkout http://svn.sqlalchemy.org/sqlalchemy/trunk sqlalchemy
cd sqlalchemy
python setup.py install --prefix /home/lucas/ENV

/home/lucas/ENV/bin/python

Activate virtual Environment

source ENV/bin/activate

Deactivate Virtual Environment

deactivate

Use Activated Virtual Environment

easy_install Elixir-0.5.2-py2.4.egg
or
easy_install SQLAlchemy
or
easy_install SQLAlchemy==dev   # for svn trunk
easy_install SQLAlchemy==0.4.5 # whatever version

Session Managment

Session ID

session_filter.on = True

import cherrypy

cherrypy.session['_id']

Install Turbogears with Apache

apache and mod_wsgi

Instructions for mod_wsgi and Turbogears were tested and are working

Install mod_wsgi

aptitude install libapache2-mod-wsgi

tar -xzvf mod_wsgi-2.0.tar.gz

aptitude update
aptitude install python-dev
aptitude install apache2-dev
aptitude install gcc

( A number of Python binary packages for Linux systems are not compiled with shared library support enabled.How can I tell?)

cd mod_wsgi-2.0
./configure
make
make install
make clean

vi /etc/apache2/mods-available/mod_wsgi.load

LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so

a2enmod mod_wsgi
/etc/init.d/apache2 force-reload

Configure your Turbogears app for mod_wsgi

  1. My application will be called 'myfirstapp'. Replace it with your application name.
  2. We will keep our project in /usr/local/turbogears/myfirtapp. You would copy your tg app to /usr/local/turbogears/.
  3. File structure will look like this:

File Structure for your app:
/usr/local/turbogears/
---------myfirstapp/ (all files from tg app)
---------myfirstapp/myfirstapp/ (main configuration files, controller.py and model.py etc)
---------myfirstapp/myfirstapp/static/ (all static files, css,images)
---------myfirstapp/prod.cfg
---------myfirstapp/apache/myfirstapp.wsgi
---------myfirstapp/server.log
and
/etc/apache2/sites-available/myfirstapp

mkdir /usr/local/turbogears

cp /home/lucas/project/myfirstapp /usr/local/turbogears
or
scp -r /home/lucas/projects/myfirstapp username@example.com/usr/local/turbogears/

mkdir /usr/local/turbogears/myfirstapp/apache

vi /usr/local/turbogears/myfirstapp/apache/myfirstapp.wsgi

import sys
sys.path.append('/usr/local/turbogears/myfirstapp')
sys.stdout = sys.stderr

import os
#os.environ['PYTHON_EGG_CACHE'] = '/usr/local/turbogears/myfirstapp'

import atexit
import cherrypy
import cherrypy._cpwsgi
import turbogears

turbogears.update_config(configfile="/usr/local/turbogears/myfirstapp/prod.cfg", modulename="myfirstapp.config")
turbogears.config.update({'global': {'server.environment': 'production'}})
turbogears.config.update({'global': {'autoreload.on': False}})
turbogears.config.update({'global': {'server.log_to_screen': False}})

#For non root mounted app:
turbogears.config.update({'global': {'server.webpath': '/myfirstapp'}})

import myfirstapp.controllers

cherrypy.root = myfirstapp.controllers.Root()

if cherrypy.server.state == 0:
    atexit.register(cherrypy.server.stop)
    cherrypy.server.start(init_only=True, server_class=None)

#For root mounted app
#application = cherrypy._cpwsgi.wsgiApp

#For none-root mounted app
def application(environ, start_response):
    environ['SCRIPT_NAME'] = ''
    return cherrypy._cpwsgi.wsgiApp(environ, start_response)

[[[access_out]]]
# set the filename as the first argument below
#args="('server.log',)"
#class='FileHandler'
level='INFO'
formatter='message_only'

sqlalchemy.pool_recycle = 3600

chown -R www-data:www-data /usr/local/turbogears/myfirstapp

vi  /etc/apache2/sites-available/myfirstapp

Alias /static /usr/local/turbogears/myfirstapp/myfirstapp/static

WSGIScriptAlias /myfirstapp /usr/local/turbogears/myfirstapp/apache/myfirstapp.wsgi

<Directory /usr/local/turbogears/myfirstapp/apache>
Order deny,allow
Allow from all
</Directory>

Turbogears and modwsgi in VirtualHost,virtualenv, and subdomain

aptitude install python-virtualenv
or 
easy_install virtualenv

mkdir /usr/local/pythonenv
python /usr/lib/python2.4/site-packages/virtualenv.py --no-site-packages /usr/local/pythonenv/BASELINE

source /usr/local/pythonenv/BASELINE/bin/activate

easy_install turbogears
easy_install sqlalchemy

mkdir /usr/local/turbogears/python-eggs

In myapp.wsgi you insert:

#For virtualenv python location
import site
site.addsitedir('/usr/local/pythonenv/BASELINE/lib/python2.4/site-packages')

import sys
sys.path.append('/usr/local/turbogears/myapp')
sys.stdout = sys.stderr

#For python egg cache
import os
os.environ['PYTHON_EGG_CACHE'] = '/usr/local/turbogears/python-eggs'

import atexit
import cherrypy
import cherrypy._cpwsgi
import turbogears

turbogears.update_config(configfile="/usr/local/turbogears/myapp/prod.cfg", modulename="myapp.config")
turbogears.config.update({'global': {'server.environment': 'production'}})
turbogears.config.update({'global': {'autoreload.on': False}})
turbogears.config.update({'global': {'server.log_to_screen': False}})

#For non root mounted app:
#turbogears.config.update({'global': {'server.webpath': '/myapp'}})

import myapp.controllers

cherrypy.root = myapp.controllers.Root()

if cherrypy.server.state == 0:
    atexit.register(cherrypy.server.stop)
    cherrypy.server.start(init_only=True, server_class=None)
#For root mounted app
application = cherrypy._cpwsgi.wsgiApp

#For none-root mounted app
#def application(environ, start_response):
#    environ['SCRIPT_NAME'] = ''
#    return cherrypy._cpwsgi.wsgiApp(environ, start_response)

<VirtualHost *>
ServerName subdomainname.example.com
ServerAlias subdomainname.*
ServerAdmin myemail@example.com

Alias /static /usr/local/turbogears/myapp/myapp/static

WSGIDaemonProcess myapp threads=10 processes=3
WSGIProcessGroup myapp

#WSGIPythonHome /usr/local/pythonenv/BASELINE
WSGIScriptAlias / /usr/local/turbogears/myapp/apache/myapp.wsgi

#<Directory /usr/local/turbogears/myapp/apache>
<Directory />
Order deny,allow
Allow from all
</Directory>

</VirtualHost>

Enable your website

* Now on debian enable your website. This file you just created will go live.

a2ensite myfirstapp

To Disable it use:

a2dissite myfirstapp

/etc/init.d/apache2 restart

easy_install -m myfirstapp

advence mod_wsgi memory management

/usr/sbin/apache2 -V

Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)
  1. apache prefork MPM = no multi threaded turbogears application
  2. apache worker MPM = multi threaded turbogears application

Overall, use of 'worker' MPM will result in less child processes needing to be created, but resource usage of individual child processes will be greater. On modern computer systems, the 'worker' MPM would in general be the preferred MPM to use and should if possible be used in preference to the 'prefork' MPM.

You are left with a choice of embded or deamon mode for your wsgi application

Unlike the normal Apache child processes when 'embedded' mode of mod_wsgi is used, the configuration as to the number of daemon processes within a process group is fixed with the settings you provide. That is, when the server experiences additional load, no more daemon processes are created than what is defined. You should therefore always plan ahead and make sure the number of processes and threads defined is adequate to cope with the expected load.

So now the question is what is max your system can coupe with and what we should start our processes and thread count.

Alias /static /usr/local/turbogears/myfirstapp/myfirstapp/static

WSGIScriptAlias /myfirstapp /usr/local/turbogears/myfirstapp/apache/myfirstapp.wsgi

<Directory /usr/local/turbogears/myfirstapp/apache>
Order deny,allow
Allow from all
</Directory>

to

Alias /static /usr/local/turbogears/myfirstapp/myfirstapp/static

WSGIDaemonProcess myfirstapp threads=10 processes=3
WSGIProcessGroup myfirstapp


WSGIScriptAlias /myfirstapp /usr/local/turbogears/myfirstapp/apache/myfirstapp.wsgi

<Directory /usr/local/turbogears/myfirstapp/apache>
Order deny,allow
Allow from all
</Directory>

Stress test your app

/usr/sbin/ab -n 1000 -w http://localhost/myfirstapp/ >> test.htm
12544  www-data  25   0  129m  21m 4604 S 33.3  4.3   0:12.08 apache2
12585  www-data  25   0  129m  21m 4604 S 32.6  4.3   0:10.75 apache2
12564 wwww-data  25   0  129m  21m 4604 S 33.3  4.3   0:12.08 apache2

then try with:

/usr/sbin/ab -n 10000 -w http://localhost/myfirstapp/ >> test2.htm

Requests per second:    10.83
Transfer rate:  67.04 kb/s received
Connnection Times (ms)
        min     avg     max
Connect:        0       0       0
Processing:     87      91      214
Total:  87      91      214

Egg deploy

Instructions for mod_proxy and Turbogears were tested and are working

Create an Egg File

cd /projects/foo
python setup.py bdist_egg

/projects/foo/dist/foo-1.0-py2.4.egg

dev.cfg app.cfg prod.cfg

dev.cfg -Has location configuration of a development database
prod.cfg -Has location configuration of a production database
app.cfg -Has custom configuration that your might need for your project app, such as template, engine, encodings, etc.

app.cfg is located in PROJECTNAME/config/app.cfg
dev.cfg is located in PROJECTNAME.dev.cfg
prod.cfg has a sample file in PROJECTNAME/sample-prod.cfg which you need to modify for production environment.

Deploy an EGG file

/var/www/foo/prod.cfg

cd /var/www/foo/eggs
easy_install foo-1.0-py2.4.egg

cd /var/www/foo
mysqladmin -h localhost -u root -p create foodb
tg-admin sql create --egg foo

Configure TurboGears prod.cfg

 server.socket_port=8080

 base_url_filter.on = True
 base_url_filter.use_x_forwarded_host = True

Run the app

# run the server
/usr/bin/foo-start.py /var/www/foo/prod.cfg

/usr/bin/foo-start.py /var/www/foo/prod.cfg &

Mod_Proxy

Enable mod proxy

domain: www.example.com
Turbogears URL: http://www.example.com/webapp/
Turbogears working on port 8080
Configuration File: prod.cfg

aptitude update
aptitude install apache2
aptitude install libapache2-mod-proxy-html

 a2enmod proxy
 a2enmod proxy_http

Configure apache

/etc/apache2/conf.d/webapp

ProxyPreserveHost on
<Proxy *>
  Order allow,deny
  Allow from all
</Proxy>
 ProxyPass /webapp/ http://127.0.0.1:8080/webapp/
 ProxyPassReverse /webapp/ http://127.0.0.1:8080/webapp/
 ProxyPass /static/ http://127.0.0.1:8080/static/
 ProxyPassReverse /static/ http://127.0.0.1:8080/static/

/etc/init.d/apache2 force-reload

Done.

Auto start of the app

@reboot /usr/bin/python /usr/bin/start-webapp.py /usr/local.bin/webapp/prod.cfg > /var/log/webapp.log &

Below instructions did not work for me. I will leave them for reference. Check the mod_wsgi instructions.

#!/usr/bin/python
print "Content-type: text/html\r\n"
print """<html><head><META HTTP-EQUIV="Refresh" CONTENT="4; URL=/webapp/"></head><body>Restarting site ...<a href="/webapp/">click here<a></body></html>"""
import os
import sys
os.setpgid(os.getpid(), 0)
os.system(sys.executable + ' /usr/bin/start-webapp.py /usr/local/bin/prod.cfg &')

<Location /recall>
# Adjust these lines and uncomment to restart the server if it isn't already running
ErrorDocument 503 /cgi-bin/webapp-autostart.cgi
ErrorDocument 502 /cgi-bin/webapp-autostart.cgi
</Location>

Server Log

What about a server log? How can I tell it to use /var/log/apache2/webapp.log How can I tell it to rotate the same way apache does it?

Troubleshooting Deployment

If you suspect or see errors that might suggests you have some sort of Python path conflicts or
permissions issues going on, or Python installation otherwise broken
in some way.

How many Python installations do you have on your system? What
versions and where?

Which installed version of Python was mod_wsgi compiled against? Which
'python' executable is in your PATH, ie., what does 'which python'
yield?

Where do you normally install Python packages/modules, ie., which site-
packages directory, or into account somehow?

How may versions of TurboGears are installed there? Are the files in
those installations all readable to others, or do they have
restrictive permissions on them such that not everyone could read
them? Apache runs as a distinct user and must be able to read them
somehow.

What is PYTHONPATH set to in your personal environment?

Do you have any Python eggs installed which are in compressed form and
would thus need to be unpacked via Python egg cache directory? Can you
clear out any Python egg cache directories you know about?

At the start of the WSGI script file, add:

 import sys
 print >> sys.stderr, sys.path

How are you restarting Apache, are you use 'sudo' or 'su' commands, if
so what is the full command line you are using?

Are you also loading mod_python into Apache at the same time?

There are various things which can cause sys.path weirdness including
having multiple versions of Python installed, local PYTHONPATH
settings and ensuring Apache doesn't inherit your personal user
environment when being started in some way.

You at least thinking about the answers to above questions and
answering them where appropriate might help to understand how you
environment is setup.

mod_python

Below instructions did not work for me. I'll leave it for reference. Check the mod_wsgi instructions

Based on: http://docs.turbogears.org/1.0/mod_python * If you don't have apache2, mod_python, you will need to install it.

aptitude update
aptitude install apache2
aptitude install libapache2-mod-python

mv /home/lucas/Desktop/modpython_gateway.py /usr/lib/python2.4/site-package/

chown root:root /usr/lib/python2.4/site-package/modpython_gateway.py

Install project file

import pkg_resources
pkg_resources.require("TurboGears")

import cherrypy
import turbogears

turbogears.update_config(modulename="myifirstproject.config")
turbogears.update_config(configfile="/home/lucas/web/myfirstproject/myfirstproject.cfg")

from myfirstproject.controllers import Root

cherrypy.root = Root()
cherrypy.server.start(initOnly=True, serverClass=None)

def fixuphandler(req):
    return 0

python setup.py install

If you get an error like this. You will need to login as root su root or use --:

Perhaps your account does not have write access to this directory?

You might have to use different installation directory by specifying --install-dir in the command.

Test project file

cd
python

inside of python type import PROJECTNAME. So in my case i would do:

import myfirstproject

Configure apache2 with your turbogears project

vi /etc/apache2/sites-enabled/myfirstproject

<Location /projectname>
    SetHandler python-program
    PythonHandler modpython_gateway::handler
    PythonOption wsgi.application cherrypy._cpwsgi::wsgiApp
    PythonFixupHandler projectname_modpython
    PythonDebug on
</Location>

/etc/init.d/apache2 restart

Error

  File "/var/lib/python-support/python2.4/turbogears/config.py", line 98, in _get_loggers
    raise ConfigError("Logger %s references unknown "

ConfigError: Logger access references unknown handler access_out

Turbogears API Details

http://tg.maetico.com/api/ Modules it covers:

Packages

turbogears
turbogears.command
turbogears.view
turbogears.view.templates
turbogears.widgets
turbogears.widgets.templates
turbogears.widgets.tests

Modules

turbogears.command.base
turbogears.command.i18n
turbogears.command.info
turbogears.command.quickstart
turbogears.config
turbogears.controllers
turbogears.database
turbogears.scheduler
turbogears.validators
turbogears.view.base
turbogears.widgets.base
turbogears.widgets.big_widgets
turbogears.widgets.datagrid
turbogears.widgets.forms
turbogears.widgets.i18n
turbogears.widgets.links
turbogears.widgets.meta
turbogears.widgets.rpc
turbogears.widgets.tests.test_datagrid
turbogears.widgets.tests.test_forms
turbogears.widgets.tests.test_link_inclusion
turbogears.widgets.tests.test_nested_form_controllers
turbogears.widgets.tests.test_nested_widgets
turbogears.widgets.tests.test_new_validation
turbogears.widgets.tests.test_request_related_features
turbogears.widgets.tests.test_widgets

Classes

turbogears.command.i18n.InternationalizationTool
turbogears.command.info.InfoCommand
turbogears.command.quickstart.BaseTemplate
turbogears.command.quickstart.quickstart
turbogears.command.quickstart.TGBig
turbogears.command.quickstart.TGTemplate
turbogears.command.quickstart.TGWidgetTemplate
turbogears.command.quickstart.TurbogearsTemplate
turbogears.command.quickstart.update
turbogears.controllers.Controller
turbogears.controllers.RootController
turbogears.database.AutoConnectHub
turbogears.database.EndTransactionsFilter
turbogears.database.PackageHub
turbogears.scheduler.DayTaskRescheduler
turbogears.scheduler.ForkedIntervalTask
turbogears.scheduler.ForkedMonthdayTask
turbogears.scheduler.ForkedScheduler
turbogears.scheduler.ForkedTaskMixin
turbogears.scheduler.ForkedWeekdayTask
turbogears.scheduler.IntervalTask
turbogears.scheduler.MonthdayTask
turbogears.scheduler.Scheduler
turbogears.scheduler.Task
turbogears.scheduler.ThreadedIntervalTask
turbogears.scheduler.ThreadedMonthdayTask
turbogears.scheduler.ThreadedScheduler
turbogears.scheduler.ThreadedTaskMixin
turbogears.scheduler.ThreadedWeekdayTask
turbogears.scheduler.WeekdayTask
turbogears.validators.DateTimeConverter
turbogears.validators.FieldStorageUploadConverter
turbogears.validators.JSONValidator
turbogears.validators.Money
turbogears.validators.MultipleSelection
turbogears.validators.Number
turbogears.validators.Schema
turbogears.validators.UnicodeString
turbogears.view.base.cycle
turbogears.view.base.DeprecatedDictWrapper
turbogears.view.base.DeprecatedVariableProviders
turbogears.view.base.MetaDeprecatedVariableProviders
turbogears.view.base.UserAgent
turbogears.widgets.base.CompoundWidget
turbogears.widgets.base.CSSLink
turbogears.widgets.base.CSSSource
turbogears.widgets.base.JSLink
turbogears.widgets.base.JSSource
turbogears.widgets.base.Link
turbogears.widgets.base.Resource
turbogears.widgets.base.Source
turbogears.widgets.base.Widget
turbogears.widgets.base.WidgetDescription
turbogears.widgets.base.WidgetsDeclaration
turbogears.widgets.base.WidgetsList
turbogears.widgets.big_widgets.AjaxGrid
turbogears.widgets.big_widgets.AutoCompleteField
turbogears.widgets.big_widgets.CalendarDatePicker
turbogears.widgets.big_widgets.CalendarDateTimePicker
turbogears.widgets.big_widgets.LinkRemoteFunction
turbogears.widgets.big_widgets.RemoteForm
turbogears.widgets.big_widgets.URLLink
turbogears.widgets.datagrid.DataGrid
turbogears.widgets.datagrid.PaginateDataGrid
turbogears.widgets.forms.Button
turbogears.widgets.forms.CheckBox
turbogears.widgets.forms.CheckBoxList
turbogears.widgets.forms.CompoundFormField
turbogears.widgets.forms.CompoundInputWidget
turbogears.widgets.forms.FieldSet
turbogears.widgets.forms.FileField
turbogears.widgets.forms.Form
turbogears.widgets.forms.FormField
turbogears.widgets.forms.FormFieldsContainer
turbogears.widgets.forms.HiddenField
turbogears.widgets.forms.ImageButton
turbogears.widgets.forms.InputWidget
turbogears.widgets.forms.Label
turbogears.widgets.forms.ListForm
turbogears.widgets.forms.MultipleSelectField
turbogears.widgets.forms.PasswordField
turbogears.widgets.forms.RadioButtonList
turbogears.widgets.forms.RepeatingFieldSet
turbogears.widgets.forms.RepeatingFormField
turbogears.widgets.forms.RepeatingInputWidget
turbogears.widgets.forms.ResetButton
turbogears.widgets.forms.SelectionField
turbogears.widgets.forms.SingleSelectField
turbogears.widgets.forms.SubmitButton
turbogears.widgets.forms.TableForm
turbogears.widgets.forms.TextArea
turbogears.widgets.forms.TextField
turbogears.widgets.i18n.CalendarLangFileLink
turbogears.widgets.i18n.LocalizableJSLink
turbogears.widgets.links.JumpMenu
turbogears.widgets.links.SyntaxHighlighter
turbogears.widgets.links.Tabber
turbogears.widgets.meta.MetaWidget
turbogears.widgets.rpc.RPC
turbogears.widgets.tests.test_datagrid.Foo
turbogears.widgets.tests.test_datagrid.TestDataGrid
turbogears.widgets.tests.test_datagrid.User
turbogears.widgets.tests.test_forms.CallableCounter
turbogears.widgets.tests.test_forms.NestedController
turbogears.widgets.tests.test_forms.Request
turbogears.widgets.tests.test_forms.w1
turbogears.widgets.tests.test_forms.w2
turbogears.widgets.tests.test_nested_form_controllers.MyRoot
turbogears.widgets.tests.test_nested_widgets.InnerSchema
turbogears.widgets.tests.test_nested_widgets.MiddleSchema
turbogears.widgets.tests.test_nested_widgets.OuterSchema
turbogears.widgets.tests.test_nested_widgets.Request
turbogears.widgets.tests.test_nested_widgets.TestNestedSchemaValidators
turbogears.widgets.tests.test_nested_widgets.TestNestedWidgets
turbogears.widgets.tests.test_nested_widgets.TestNestedWidgetsWMixedValidation
turbogears.widgets.tests.test_nested_widgets.TestNestedWidgetsWSchemaValidation
turbogears.widgets.tests.test_nested_widgets.TestSchema
turbogears.widgets.tests.test_new_validation.NotSoSimpleSchema
turbogears.widgets.tests.test_new_validation.Request
turbogears.widgets.tests.test_new_validation.SimpleFields
turbogears.widgets.tests.test_new_validation.SimpleFieldSet
turbogears.widgets.tests.test_new_validation.SimpleForm
turbogears.widgets.tests.test_new_validation.SimpleSchema
turbogears.widgets.tests.test_new_validation.TestNestedForm
turbogears.widgets.tests.test_new_validation.TestSimpleForm
turbogears.widgets.tests.test_widgets.A
turbogears.widgets.tests.test_widgets.B
turbogears.widgets.tests.test_widgets.C
turbogears.widgets.tests.test_widgets.Fields
turbogears.widgets.tests.test_widgets.Fields
turbogears.widgets.tests.test_widgets.FieldsSchema
turbogears.widgets.tests.test_widgets.FieldsSchema
turbogears.widgets.tests.test_widgets.Request
turbogears.widgets.tests.test_widgets.TestParams
turbogears.widgets.tests.test_widgets.TestSchemaValidation
turbogears.widgets.tests.test_widgets.TestSchemaValidationWithChildWidgetsValidators

Performance

Genshi vs other

maco vs Cheetah

from maco website:
 Mako:   1.10 ms         Myghty: 4.52 ms
 Cheetah:1.10 ms         Genshi: 11.46 ms
 Django: 2.74 ms         Kid:    14.54 ms

Sqlalchemy vs storm

Errors

TgFastData for python 2.5

easy_install http://svn.turbogears.org/projects/FastData/trunk

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

from sqlobject import *

class Book(SQLObject):
    class sqlmeta:
        fromDatabase = True

Flash status Bar

http://www.splee.co.uk/2005/11/23/fancy-status-messages-using-tg_flash/

Tagging with Turbogears

http://www.thesamet.com/blog/2006/11/17/tutorial-how-to-implement-tagging-with-turbogears-and-sqlalchemy/

Drag and Drop Sort list

http://wiki.script.aculo.us/scriptaculous/show/SortableListsDemo

Turbogears and Oracle

http://www.oracle.com/technology/pub/articles/rubio-python-turbogears.html

Turbogears memory managment

http://psychicorigami.com/2007/10/27/a-little-sqlobject-performance-guide/ http://psychicorigami.com/2007/12/16/using-raw-sql-with-sqlobject-and-keeping-the-object-y-goodness/

unixODBC

aptitude update
aptitude install tdsodbc unixodbc

vi /etc/freetds/tds.driver.template

[TDS]
Description     = FreeTDS Driver for Linux & MSSQL on Win32
Driver          = /usr/lib/odbc/libtdsodbc.so
Setup           = /usr/lib/odbc/libtdsS.so

vi /etc/freetds/tds.dsn.template

[DSN_NAME]
Description     = Descripton of you DSN connection.
Driver          = TDS
Trace           = No
Database        = DefaultDatabase [replace with your database name]
Server          = mysqlserver.inter.net [replace with your SQL server's host,ip]
Port            = 1433 [replace with the port that SQL is listening on]

odbcinst -i -d -f /etc/freetds/tds.driver.template

odbcinst -i -s -l -f /etc/freetds/tds.dsn.template

odbcinst -i -s -f /etc/freetds/tds.dsn.template

isql -v DSN_NAME username password

**********************************************
* unixODBC - isql                            *
**********************************************
* Syntax                                     *
*                                            *
.
.
.
more
.

Authenticating against an external password source

http://docs.turbogears.org/1.0/IdentityManagement#authenticating-against-an-external-password-source

Embed swf files in your turbogears code (IE, Opera, Firefox etc)

SQLObject (SO) quick Overview

tg-admin quickstart

dev.conf -database connection

sqlobject.dburi="mysql://username:password@localhost:3306/databasename

model.py -database model

#Create database object from a database
class mainapplication(SQLObject):
    _idName = "App_Sid"
    class sqlmeta:
        fromDatabase = True

sqlobject features

Design

Naming convention:

class Addressbook(SQLObject):
    class sqlmeta:
        style=MixedCaseStyle()

Lazy Update and Caching of connection object

cacheValues - sets the number of cache values
lazyUpdate - will waits with an update until sync command is issued
sync() -sync with database
syncUpdate() -syncs and updates database

sql attributes

def  _get_totalfee(self):
    return eval(self.fees)

Transactions

#This creates transaction object
trans = conn.transaction()
#set connection for your table
for x in mySqlClass:
    x._connection=trans

def sell(item):
    try:
        books=BookStore.selectBy(book=item)[0]
        books.quantity-= 1
        SoldBooks(item=item)
        trans.commit()
    except Exception, e:
        trans.rollback()
        trans.begin()

SQLObject save to database

Example1

class PhoneBook(SQLObject):
    first_name=StringCol(alternateID=True, length=30)
    last_name=StringCol()
    home_page=StringCol(legth=255)

#Simple save. PhoneBook(first_name="John",last_name="Smith",home_page="www.example.com") }}}

Turbogears Specifics usage

Use CAPITAL names in widgets and sqlalchemy autoload

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)

But when I want to prefill the widget form with values from sqlalchemy using:

 <p><span>${address(value=value, action=action)}</span></p>

The values are not set Am I missing something here or values from sqlalchemy query do not correspond to widget fields?

It seems as it does but it needs to be the same case.

So I went into my widget class and I replaced the
"City" with "CITY" which caused the value to fill in.

It is the same case when saving from widget to sqlalchemy. If your widget doesn't have CAPITAL names then you have to convert them.

def saveuser(self,**kwargs):
    from string import upper
    b.USER_SID=(int(max_id)+1)
    #Assigning rest of the keys
    for widgetkey in kwargs.keys():
        j=upper(widgetkey)
        setattr(b,j,kwargs[widgetkey])

CONCLUSION: When using sqlalchemy and widgets we need to name our attributes in the widget using CAPITAL letters. when we use sqlalchemy autoload function.

sqlalchemy:

user_table = sqlalchemy.Table('user', metadata, autoload=True)

widget:

class User(widgets.WidgetsList):
    LASTNAME=widgets.TextField(label='Last Name',validator=validators.NotEmpty)
    FIRSTNAME=widgets.TextField(label='First Name',validator=validators.NotEmpty)

WAS THIS INTENDED? If not should it be documented somewhere or changed? 1-15-08. update. I just loaded my table a table with all lowercase and I didn't need all capital letters. There has to be some kind of exception.

redirect all requests to index

    @expose()
    def default(self, *args, **kw):
        return self.index(*args,**kw)

Other Documentation

IBM

  1. Turbogears by IBM

ORACLE

  1. Turbogears by Oracle

Common Errors

non-keyword arg after keyword arg

SyntaxError: non-keyword arg after keyword arg

BAD:

x2=sqlalchemy.select([Users.c.AGE], group_by=[Users.c.AGE],Users.c.LASTNAME=='Smith')

GOOD:

x2=sqlalchemy.select([Users.c.AGE], Users.c.LASTNAME=='Smith',group_by=[Users.c.AGE])

cherrypy._cperror.NotReady: Port not free

server.socket_port=8080

and change it to

server.socket_port=8081

then python start_yourproject.py

ExpatError: not well-formed (invalid token)

Replace "&" with "&amp;"
<a href="http://www.google.com/search?hl=en&q=schools+near+60630&btnG=Google+Search">mylink</a> (bad)
<a href="http://www.google.com/search?hl=en&amp;q=schools+near+60630&amp;btnG=Search">mylink</a> (good)

Could not assemble any primary key columns for mapped table

MyWiki: TurboGears (last edited 2009-04-06 13:35:08 by LukaszSzybalski)