The model options
A model is declared with its fields, and the rest is a list of options. The tour covers the main ones as it goes. Eight are named nowhere, although they change visibility, navigation or the screen.
read_open: reference data
A product, a partner, a unit, a currency are read by roles from every module. Listing each role in the read permission is unmaintainable and breaks the moment a module arrives (rule 8).
registry.register_model("library_title", module="library", read_open=True, fields=[...])Run with a user who belongs to no group at all:
without read_open: with read_open=True: GET /library_title -> 200 [] GET /library_title -> 200 [Dune, ...] GET /library_title/1 -> 404 GET /library_title/1 -> 200 POST /library_title -> 403 POST /library_title -> 403Two things to take from that table:
- writing does not move.
read_openopens reading and nothing else: creating is still refused by the model’s permission; - without read permission a list answers 200 and empty, not 403. A single record answers 404, not 403. The kernel filters instead of refusing, and never tells someone a record exists when they may not see it. A module expecting a 403 on the list expects the wrong thing.
14 of the product’s modules use this option.
menu_groups: readable without being in the menu
By default any group that can read a model sees it in the navigation. That is not always wanted: a technical model must stay readable (otherwise the dropdowns pointing at it break) without cluttering everybody’s menu.
registry.register_model("library_shelfmark", module="library", menu_groups=("library_librarian",), ...)The navigation shows it to librarians only; permissions do not change. It is screen tidying, never security. 12 modules use it.
ui_managed: records you do not create by hand
Some records are born from a controlled flow (a state transition’s effect, a generated entry) and
never from a “New” button. With ui_managed=True the interface drops the create / edit / delete
affordances, the list stays visible as history, and the real permissions do not change:
server-side writes still go through.
settings: configuration, not data
A model marked settings=True is placed by the frontend under Settings instead of the
module’s business navigation. Purely navigational: permissions, rules and storage are untouched.
create_route: your own create screen
create_route="/forms/new/edit"The generic “New” no longer opens: it redirects to your screen. A form built by assembling blocks has no business inside a generic field form. Everything else (permissions, API) is unchanged: it is a discovery option, not a back door.
image_field and image_fallback: the thumbnail
image_field names the file field used as a thumbnail, and that alone makes the gallery view
appear, with no configuration. image_fallback takes over when the record has no image of its
own:
image_field="photo", image_fallback=("user_id", "avatar_file")An employee with no photo shows their user’s avatar. One relation, one field, and no if in the
interface.
path_field: hierarchies
Declares which field stores the parent-chain path, and how to build it. The session recomputes
it for a moved record and all its descendants, so it never drifts. Rendered read-only in
views: it is not something you type.
per_website: several storefronts in one tenant
Adds a website_id column and partitions records per public site. No business module uses it
today: it is a kernel option for multi-site storefronts, named here so it stops being invisible.