I'm attempting to dynamically build tables known as db.blog and db.code with the identical SQL definitions. Once I define them, I wish to populate all of them with 10 rows of random data, rather than execute that initialization code again.

My problem would be that the initialization code executes each time I hit refresh around the browser as i see the newblog appadmin interface for db.code or db.blog: https://172.25.1.1/newblog/appadmin/select/db?query=db.code.id>0

I initialize db.blog and db.code in newblog/models/newblog.py:

from gluon import *
from gluon.contrib.populate import populate

## initialize db.blog and db.code: 
##     At runtime, build TAGGED_TABLES (once)
TAGGED_TABLES = set(['blog', 'code'])
for tt in TAGGED_TABLES:
    if not db.get(tt, False):
        db.define_table(tt,
            Field('name', length=32, notnull=True),
            Field('value', length=65535, notnull=True),
            Field('tags', type='list:reference tag', unique=False, notnull=False),
            )

        populate(db.get(tt), 10)

        ## cross-reference db.tagged_tables to this one
        db.tagged_tables.insert(name=tt,
            database_pointer='reference %s' % tt)
        db.commit()

In some way if not db.get(tt, False): enables multiple accomplishments from the routine below it. I do not realise why... when the table was already produced, then not db.get(tt, False) ought to be False. However, web2py never skips the initialization code, meaning db.blog and db.code grow by 10 records on each reload.

Question: Why is not if not db.get(tt, False): stopping multiple accomplishments?

I'm running web2py 1.99.4 on Debian 6. / sqlite 3.7.3 / Cherokee 1.2.101 / uWSGI .9.9.3

Solution

According to Interrobang's answer the right way to create this really is:

from gluon import *
from gluon.contrib.populate import populate


TAGGED_TABLES = set(['blog', 'code'])
for tt in TAGGED_TABLES:
    # db.define_table() must be called on **every page**
    #    this sets things up in memory...
    db.define_table(tt,
        Field('name', length=32, notnull=True),
        Field('value', length=65535, notnull=True),
        Field('tags', type='list:reference tag', unique=False, notnull=False),
        )

    ## initialize db.blog and db.code: 
    ##     At runtime, populate tables named in TAGGED_TABLES (once)
    if not (db(db.get(tt).id>0).select()):
        populate(db.get(tt), 10)
        ## cross-reference db.tagged_tables to this table (named in var tt)
        db.tagged_tables.insert(name=tt,
            database_pointer='reference %s' % tt)
        db.commit()

Now db.blog and db.code stay a continuing size.

Summary

db.define_tables() should be known as for each page rendering my understanding (it only required to run once to create the table definition to disk) was incorrect.

You can include a fittings file, which essentially consists of default data to become placed once, once the table is produced.

A good example is offered here: http://thadeusb.com/weblog/2010/4/21/using_fixtures_in_web2py