Search code examples
data-access-layerweb2py

does web2py's DAL automatically create forward references when a child table references the parent?


The following information is from page 270 of the web2py book:

person = db.person(id)

for dog in person.dog.select(orderby=db.dog.name):
    print person.name, 'owns', dog.name

In this last expressions person.dog is a shortcut for

db(db.dog.owner==person.id)

Now:

The book does not reference a section where the person table is defined and I dont believe any prior definition of that table actually had a dog column. And it wouldnt make sense if the person table did have a dog column, because presumably a person can have many dogs.

So are they saying that somehow the reference from the dog table to person automatically created a forward reference from the person to the dog, without any explicit column in person?


Solution

  • Nothing was automatically created in the "person" database table itself. Rather, the DAL Row object representing the record of a given person includes a DAL Set object that represents the set of records in the "dog" table that reference the person. In the code, person is a Row object (i.e., db.person(id)) -- it has a "dog" attribute, which is just the following DAL Set object:

    db(db.dog.owner == person.id)
    

    which is the set of dogs that reference this person.id. If you do:

    >>> print db.person(1)
    

    you'll see something like:

    <Row {'name': 'John', 'update_record': <function <lambda> at 0x2b08758>,
    'dog': <gluon.dal.Set object at 0x2b00d10>, 'id': 1,
    'delete_record': <function <lambda> at 0x2b08b90>}>
    

    So, in addition to containing the "name" and "id" values for the record, the Row object includes update_record() and delete_record() functions as well as a Set object representing the "dog" table records that reference this person. If you print the query associated with that Set object, you get the following:

    >>> print db.person(1).dog.query
    (dog.owner = 1)
    

    So, the forward reference is created in the Row object itself. Note, the db.person(1).dog attribute is only a Set object defining a query -- it does not contain the actual "dog" table records or even references to their id's. No query is done against the database until you call the select() method via db.person(1).dog.select(), which will return the actual records from the "dogs" table.