Gazpachoexample3

Here is an example of two database entities which share a one-to-one relationship. This example uses alternateID's in the user interface.

This example uses SQLObject r865, pysqlite 2.0.2, and gazpacho 0.5.3

db_schema.py:

#!/usr/bin/python

from sqlobject import *
import os
conn = connectionForURI("sqlite://" + os.getcwd() + "/database.db")

class Person(SQLObject):
    _connection = conn

    # attributes
    name = StringCol(notNone=True, alternateID=True)

    # relationships
    toaster = SingleJoin('Toaster') # Person has one Toaster


class Toaster(SQLObject):
    _connection = conn

    # attributes
    color = StringCol(notNone=True, alternateID=True)

    # relationship
    person = ForeignKey('Person') # Person has one Toaster

initialize_db.py:

#!/usr/bin/python

from db_schema import *

Person.createTable()
Toaster.createTable()

Person(name="john")
Person(name="bob")
Toaster(color="blue",person=None)
Toaster(color="green",person=None)

person.py:

#!/usr/bin/python

import pygtk
pygtk.require('2.0')
import gtk

from gazpacho.loader.proxy import Proxy
from db_schema import *

from gtk_util import *

class PersonEditor(Proxy):
    def __init__(self,person_id):
        Proxy.__init__(self, gladefile="person.glade")

        # connect to db
        self.person = Person.get(person_id)

        # name entry
        if self.person.name != None:
            self.name_entry.set_text(self.person.name)

        # toaster combo
        toaster_list = [toaster.color for toaster in Toaster.select()]
        combo_fill_text(self.toaster_combo, toaster_list)
        if self.person.toaster != None:
            combo_set_from_db(self.toaster_combo, self.person.toaster.color)

    def on_window1__destroy(self, window):
        gtk.main_quit()

    def on_name_entry__changed(self,widget):
        self.person.name = widget.get_text()

    def on_toaster_combo__changed(self, widget):
        if self.person.toaster != None:
            self.person.toaster.person = None
        toaster_color = combo_get_value(widget)
        toaster = Toaster.byColor(toaster_color)
        toaster.person = self.person.id


if __name__ == "__main__":
    import sys
    assert len(sys.argv) >= 2
    person_id = int(sys.argv[1])
    app = PersonEditor(person_id)
    gtk.main()

person.glade:

<?xml version="1.0" ?>
<glade-interface>
    <widget class="GtkWindow" id="window1">
        <property name="events"></property>
        <property name="visible">True</property>
        <child>
            <widget class="GtkFrame" id="frame1">
                <property name="label" context="True" translatable="True">Person</property>
                <property name="events"></property>
                <property name="label_xalign">0.0</property>
                <property name="visible">True</property>
                <child>
                    <widget class="GtkTable" id="table1">
                        <property name="n_rows">2</property>
                        <property name="n_columns">2</property>
                        <property name="visible">True</property>
                        <child>
                            <widget class="GtkComboBox" id="toaster_combo">
                                <property name="visible">True</property>
                            </widget>
                            <packing>
                                <property name="left_attach">1</property>
                                <property name="bottom_attach">2</property>
                                <property name="top_attach">1</property>
                                <property name="right_attach">2</property>
                            </packing>
                        </child>
                        <child>
                            <widget class="GtkLabel" id="toaster_label">
                                <property name="label" translatable="True">toaster</property>
                                <property name="visible">True</property>
                            </widget>
                            <packing>
                                <property name="bottom_attach">2</property>
                                <property name="top_attach">1</property>
                            </packing>
                        </child>
                        <child>
                            <widget class="GtkEntry" id="name_entry">
                                <property name="events"></property>
                                <property name="can_focus">True</property>
                                <property name="visible">True</property>
                            </widget>
                            <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                            </packing>
                        </child>
                        <child>
                            <widget class="GtkLabel" id="name_label">
                                <property name="label" context="True" translatable="True">name</property>
                                <property name="events"></property>
                                <property name="visible">True</property>
                            </widget>
                            <packing/>
                        </child>
                    </widget>
                </child>
            </widget>
        </child>
    </widget>
</glade-interface>

toaster.py:

#!/usr/bin/python

import pygtk
pygtk.require('2.0')
import gtk

from gazpacho.loader.proxy import Proxy
from db_schema import *

from gtk_util import *

class ToasterEditor(Proxy):
    def __init__(self,toaster_id):
        Proxy.__init__(self, gladefile="toaster.glade")

        # connect to db
        self.toaster = Toaster.get(toaster_id)

        # color entry
        if self.toaster.color != None:
            self.color_entry.set_text(self.toaster.color)

        # person combo
        person_list = [person.name for person in Person.select()]
        combo_fill_text(self.person_combo, person_list)
        if self.toaster.person != None:
            combo_set_from_db(self.person_combo, self.toaster.person.name)

    def on_window1__destroy(self, window):
        gtk.main_quit()

    def on_color_entry__changed(self,widget):
        self.toaster.color = widget.get_text()

    def on_person_combo__changed(self, widget):
        person_name = combo_get_value(widget)
        person = Person.byName(person_name)
        if person.toaster != None:
            person.toaster.personID = None
        self.toaster.personID = person.id


if __name__ == "__main__":
    import sys
    assert len(sys.argv) >= 2
    toaster_id = int(sys.argv[1])
    app = ToasterEditor(toaster_id)
    gtk.main()

toaster.glade:

<?xml version="1.0" ?>
<glade-interface>
    <widget class="GtkWindow" id="window1">
        <property name="events"></property>
        <property name="visible">True</property>
        <child>
            <widget class="GtkFrame" id="frame1">
                <property name="label" context="True" translatable="True">Toaster</property>
                <property name="events"></property>
                <property name="label_xalign">0.0</property>
                <property name="visible">True</property>
                <child>
                    <widget class="GtkTable" id="table1">
                        <property name="n_rows">2</property>
                        <property name="n_columns">2</property>
                        <property name="visible">True</property>
                        <child>
                            <widget class="GtkComboBox" id="person_combo">
                                <property name="visible">True</property>
                            </widget>
                            <packing>
                                <property name="left_attach">1</property>
                                <property name="bottom_attach">2</property>
                                <property name="top_attach">1</property>
                                <property name="right_attach">2</property>
                            </packing>
                        </child>
                        <child>
                            <widget class="GtkEntry" id="color_entry">
                                <property name="visible">True</property>
                            </widget>
                            <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                            </packing>
                        </child>
                        <child>
                            <widget class="GtkLabel" id="person_label">
                                <property name="label" translatable="True">person</property>
                                <property name="visible">True</property>
                            </widget>
                            <packing>
                                <property name="bottom_attach">2</property>
                                <property name="top_attach">1</property>
                            </packing>
                        </child>
                        <child>
                            <widget class="GtkLabel" id="color_label">
                                <property name="label" translatable="True">color</property>
                                <property name="visible">True</property>
                            </widget>
                            <packing/>
                        </child>
                    </widget>
                </child>
            </widget>
        </child>
    </widget>
</glade-interface>

gtk_util.py:

import gtk

def combo_fill_text(combo_widget, content_list):
    liststore = gtk.ListStore(str)
    combo_widget.set_model(liststore)
    cell = gtk.CellRendererText()
    combo_widget.pack_start(cell, True)
    combo_widget.add_attribute(cell, 'text', 0)
    for item in content_list:
        combo_widget.append_text(item)

def combo_set_from_db(combo_widget, db_item):
    list_model = combo_widget.get_model()
    iter = list_model.get_iter_first()
    while list_model.get_value(iter,0) != db_item:
        iter = list_model.iter_next(iter)
    combo_widget.set_active_iter(iter)

def combo_get_value(widget):
    list_model = widget.get_model()
    iter = widget.get_active_iter()
    return list_model.get_value(iter,0)