circular refereces in py4web/DAL

45 views
Skip to first unread message

Marvi Benedet

unread,
Jun 4, 2026, 1:06:10 PM (9 days ago) Jun 4
to py4web
Hi,
I'm migrating an application from web2py to py4web.
I have some circular refereces in the database definition. 
With web2py, this problem was somehow solved.

Don't remember exactly how, but I think that in web2py the "lazy_tables = True"  parameter helped. 

In py4web there are 2 scenarios:

without lazy_tables I get: 

[FAILED] loading appname ('Cannot resolve reference firmware in device_model definition') 
at startup.

with lazy_tables = True I get no error at startup, but when app tries to use them. 

Is there a way to resolve this?



db.define_table('device_model',
                Field('name', length=100),
                Field('default_firmware', 'reference firmware')
                )

db.define_table('device_model_firmware',
                Field('version', length=100),
                Field('filename', length=100),
                Field('model', 'reference device_model')
                )

Marvi Benedet

unread,
Jun 4, 2026, 1:10:15 PM (9 days ago) Jun 4
to py4web
sorry, there  is an error in the reference, this is the correct example:

db.define_table('device_model',
                Field('name', length=100),
                Field('default_firmware', 'reference device_model_firmware')
                )

db.define_table('device_model_firmware',
                Field('version', length=100),
                Field('filename', length=100),
                Field('model', 'reference device_model')
                )

Marvi Benedet

unread,
Jun 5, 2026, 4:19:57 AM (9 days ago) Jun 5
to py4web
I figured out how to create circular reference in Web2py:

- Create tables definition as below, note that the reference definition in the first table is commented.
- Open a generic page on the app in order to create the tables.
- Decomment the reference field
- (re)open a generic page on the app

table is updated and the reference is now present. 

Unfortunately, the same procedure in Py4web doesn't seems to work. 


# .....
# Web2py Version 2.27.1-stable
# lazy_tables = True,

db.define_table('device_model',
                Field('name', length=100),
                #Field('default_firmware', 'reference device_model_firmware')
                )

db.define_table('device_model_firmware',
                Field('version', length=100),
                Field('filename', length=100),
                Field('model', 'reference device_model')
                )
db.device_model
db.device_model_firmware

#.....

Luc Chase

unread,
Jun 5, 2026, 5:48:44 PM (8 days ago) Jun 5
to py4web
What do you mean by 'circular reference'  ?     What business rule are you trying to implement?  e.g. Is it that one device_model can have only 0 or 1 of device_model_firmare  ?

Alan Etkin

unread,
Jun 6, 2026, 9:00:40 AM (8 days ago) Jun 6
to py4web
I think I had this issue and a workaround could be the following:

1) Define your model but remove reference fields from the table definitions
2) Run the app once so the db connection files are built
3) Re-define the model adding the foreign key fields
4) Run again the app with the new fields

Then, py4web should automatically rewrite the db connection files to support the references, and also call SQL commands on db engine to update table definitions.

Regards

Alan

Marvi Benedet

unread,
Jun 9, 2026, 2:10:59 PM (4 days ago) Jun 9
to py4web
Hello, 
this is the best workaround that I found until now:

db.define_table('device_model',
                Field('name', length=100),
                Field('default_firmware', 'integer'),
                format='%(name)s',
                )

db.define_table('device_model_firmware',
                Field('version', length=100),
                Field('filename', length=100),
                Field('model', 'reference device_model', ondelete='SET NULL', requires=IS_IN_DB(db, 'device_model.id','%(id)s - %(name)s')),
                )

db.define_table('device_model',
                Field('name', length=100),
                Field('default_firmware', 'integer', requires=IS_EMPTY_OR(IS_IN_DB(db, 'device_model_firmware.id','%(version)s: %(filename)s'))),
                redefine = True
                )


I redeclared the "device_model" table adding the requirements on the missing (pseudo)reference. 
Now I get the typical reference advantages on forms.

For example with this controller:
@action('model/edit/<model_id:int>',  method=["GET", "POST"])
@preferred('forms/device_edit_form.html')
def model_edit(model_id):
    record = db.device_model(model_id)
    db.device_model_firmware._common_filter = lambda query: db.device_model_firmware.model==model_id
    form = Form(db.device_model, record=record)
    if form.accepted:
        redirect(URL('list'))  # redirect after save
    return dict(form=form)


the result is: (the drop down menu shows the correct list of firmwares of the selected model)
immagine.png

I'm not certain this is the best approach,
I would appreciate hearing from the developers if there is an official position regarding circular references.

Reply all
Reply to author
Forward
0 new messages