Py4Web in Production

45 views
Skip to first unread message

Rakesh Singh

unread,
Aug 29, 2026, 6:15:32 AM (6 days ago) Aug 29
to py4web
Hi all,

Apologies in advance for the long message :-)

Having used web2py in a previous role in the 2010's, I decided to use py4web for a very small application our users required. The team originally had a prototype in Flask and wanted to switch to Django, but web2py's grid and DAL would fast-track the development so I went with that.
I created the app with the then latest 1.20231115.1 release.
The users recently got a security company to perform a pen-test, and I really don't buy the findings.
Unfortunately, I cannot share the results, but it claims SQL injection and script execution is possible in the search field of the Grid, among other very minor issues.

I decided to upgrade the latest py4web 1.20260805.0, add the new functionality and run some security testing of my own (as much as I am able to with limited pen-test knowledge).

However, I have been struggling with the upgrade for almost 2 weeks.
AD authentication was failing, as well as migration of the production database schema on development, record versioning, pre-action buttons etc.
The hidden fields in the forms don't seem to be working and I haven't fixed that yet. So I've got some disgruntled colleagues at the moment :)

Should I have used web2py for this application?
And if py4web is production-ready, what would be the recommended approach to ensure upgrades can be done with minimal issues?

Thank you.

Rakesh Singh

unread,
Aug 29, 2026, 11:41:40 AM (6 days ago) Aug 29
to py4web
Encountered another issue during testing. 
"list:reference <table>", multiple=True

Defining a column as list:reference does not to return any records in my grid, and no errors or warnings are returned.
Changing it to "reference <table>" then works, but I need to allow for multiple selections.
It does work with 20231115.1

Rakesh Singh

unread,
Aug 29, 2026, 11:45:10 AM (6 days ago) Aug 29
to py4web
Regarding the hidden fields in my forms, I had a look at forms.py in the old production py4web installation, and it seems that the current version does not add the hidden fields to form.vars.
I wasn't sure of if this feature is being deprecated, so I am resorted to re-reading the fields I require from the database with the form handler.

Rakesh Singh

unread,
Aug 29, 2026, 2:08:03 PM (6 days ago) Aug 29
to py4web
I had to use OpenCode to try and help with the list:reference issue using a test app. The workaround does seem to work.


Screenshot_2026-08-29_20-05-12.png

cat models.py
─────┬─────────────────────────────────────────────────────────────────────────────────────────────────
     │ File: models.py
─────┼─────────────────────────────────────────────────────────────────────────────────────────────────
   1 │ """
   2 │ This file defines the database models
   3 │ """
   4 │
   5 │ from pydal.validators import *
   6 │
   7 │ from .common import Field, db
   8 │
   9 │ db.define_table("cars",
  10 │                 Field("car_make", "string", help="Car Make & Model",
  11 │                       required=True, unique=True,
  12 │                       format="%(car_make)s")
  13 │                 )
  14 │
  15 │ db.define_table("owner",
  16 │                 Field("owner_name", "string", required=True),
  17 │                 Field("cars", "list:reference cars", multiple=True)
  18 │                 )
  19 │
  20 │
  21 │ # --- Workaround: make "cars" display as a list of car names ---
  22 │ # This pydal version does not derive <table>._format from a field's format,
  23 │ # and list:reference fields do not get a default represent/validator here.
  24 │ # Set them explicitly so Grids and Forms render a list of cars instead of ids.
  25 │ db.cars._format = lambda r: r.get("car_make") or r.id
  26 │ db.owner.cars.requires = IS_IN_DB(db, "cars.id", db.cars._format, multiple=True)
  27 │ db.owner.cars.represent = (
  28 │     lambda value, row=None: ", ".join(
  29 │         db.cars._format(db.cars(v)) for v in (value or [])
  30 │     )
  31 │     if value
  32 │     else ""
  33 │ )
  34 │
  35 │ db.commit()
  36 │
Reply all
Reply to author
Forward
0 new messages