wiki:ListWidgetFromForeignKey
Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

This recipe uses TurboGears SVN Revision 458 and SQLObject 0.7.

TurboGears includes a controller, turbogears.fastdata.DataController that takes an SQLObject class as an argument and produces a CRUD interface. This recipe produces a select form element when it encounters a foreign key of a class with the form_option_value defined. Included is the model and controllers you will need with code to create and populate the database tables. You'll need to define your database info in dev.cfg. Otherwise, it's batteries included.

# model.py
from turbogears.fastdata import formmaker
from turbogears.database import PackageHub
from turbogears import widgets
from sqlobject import *
from sqlobject.col import SOKeyCol

hub = PackageHub("your_package")
__connection__ = hub

@formmaker.column_widget.when("isinstance(column, SOKeyCol)")
def column_widget_fk_col(column):
    parms = formmaker.column_parms(column)
    fk_class_name = column.foreignKey
    fk_class = classregistry.findClass(fk_class_name)
    fk_class_data = fk_class.select()
    if hasattr(fk_class, 'form_option_value'):
        options = [[rset.id, rset.form_option_value] for rset in
fk_class_data]
        return_widget = widgets.SelectField(validator=None, options=options,
                                            **parms)
    else:
        return_widget =  widgets.TextField(validator=None, **parms)
    # For some reason, if I don't do this, I get stuck in a transaction.
    hub.commit()
    return return_widget


class Item(SQLObject):
    name = StringCol(length=200)
    
    def _get_form_option_value(self):
        # This lets turbogears know what to use for the option element value.
        # Could this also be used to populate the DataGrid?
        return self.name

class Sale(SQLObject):
    item = ForeignKey('Item', title='Item')
    quantity = IntCol(default=1)

def setUpTables():
    # Create and populate the tables.
    hub.begin()
    Sale.dropTable(ifExists=True, cascade=True)
    Item.dropTable(ifExists=True, cascade=True)
    hub.commit()
    Item.createTable(ifNotExists=True)
    Sale.createTable(ifNotExists=True)
    items = Item.select()
    Item(name='Deoderant')
    Item(name='Shoes')
    Item(name='Milk')
    Item(name='Golf Balls')
    hub.commit()
setUpTables()
# controllers.py
import turbogears
from turbogears import controllers
from turbogears.fastdata import DataController

from model import Sale, Item

# Just for ease of use.
index_html="""
<html>
<body>
<a href="items/">Items</a>
<br />
<a href="sales/">Sales</a>
</body>
</html>
"""

class Root(controllers.Root):
    sales = DataController(Sale)
    items = DataController(Item)

    @turbogears.expose()
    def index(self):
        return index_html