Reputation: 1210
I'm new to Web2py and SQL Databases in general, so forgive me if this is a dumb question.
What I'm trying to do is create a form that pulls relevant data (type, label, IS_NOT_EMPTY(), etc.) from an SQL table's field to populate and configure input elements on the frontend. So far I've successfully been able to do this using the Web2py Manual as an excellent reference.
I've gotten to the point where I'd like to use multiple tables to help categorize sets of data more effectively. Best case scenario would be to have one master table that can be called in my controller file (default.py), that is linked with other relevant (but not always needed) tables in my db.
In the below code you can see that I define the 'category_t' table first, then define the 'new_product' table. I then attempt to reference 'category_t' table within the 'main_category' field on new_product. The 'main_category' field ends up being a multiple select element on the form, which is exactly what I want. I just need to use the field labels from 'category_t' as the multi-select options.
I was using this Links to referencing records instructions from the Web2py Manual, but I believe I'm misinterpreting what it's actually capable of. I desperately need someone to school me on the laws of Web2py and SQLite.
db.define_table(
'category_t',
Field('category1', 'boolean', label='Category 1'),
Field('category2', 'boolean', label='Category 2'),
Field('category3', 'boolean', label='Category 3'),
)
db.define_table(
'new_product',
Field('name', requires=[IS_NOT_EMPTY(), IS_ALPHANUMERIC()], label='Product Name'),
Field('sku', requires=[IS_NOT_EMPTY(), IS_ALPHANUMERIC()], label='SKU'),
Field('build', requires=IS_IN_SET(['Build1','Build2','Build3']), label='Product Type'),
Field('main_category', 'list:reference category_t', label='Category'),
)
I have discovered that it's as easy as adding the ancillary table within your main table to get it to display on the front end. I have not yet checked whether it's able to update without error.
db.define_table(
'new_product',
Field('name', requires=[IS_NOT_EMPTY(), IS_ALPHANUMERIC()], label='Product Name'),
Field('sku', requires=[IS_NOT_EMPTY(), IS_ALPHANUMERIC()], label='SKU'),
Field('build', requires=IS_IN_SET(['Build1','Build2','Build3']), label='Product Type'),
db.category_t
)
I have not yet figured out how to display it as a multi-select element. As of right now, it displays as a series of check boxes.
Upvotes: 1
Views: 1367
Reputation: 25536
The code in your update is not doing what you think it is doing. By adding db.category_t
to the new_product
table definition, you are simply adding a completely separate set of category fields to the new_product
table. The data for those fields will be stored in the new_product
table, and nothing will be stored in the category_t
table. If you just want a small fixed set of boolean category fields, then the category_t
table is unnecessary -- you should just define those fields in new_product
. However, each category will be a separate input, so you will not have a single multi-select.
Probably what you want instead is a list:string
or list:reference
field. The simplest approach is a list:string
field:
db.define_table('new_product', ...,
Field('main_categories', 'list:string', label='Categories',
requires=IS_IN_SET(['Category 1', 'Category 2', 'Category 3'],
multiple=True)))
The above will store a list of category names in the main_categories
field, and the IS_IN_SET validator will restrict the options to a particular set of categories, which will be displayed in a mult-select box (due to the multiple=True
argument). No need for a separate category table in this case.
If you want to maintain a separate category table for some reason (e.g., there is some metadata associated with each category, or you expect to be editing the category names frequently), you can instead use a list:reference
field. However, the category table should not be defined as in your example, but should have a separate record for each category:
db.define_table('category',
Field('name'),
[other category metadata fields if needed],
format='%(name)s')
db.define_table('new_product', ...,
Field('main_categories', 'list:reference category', label='Categories')
In this case, the main_categories
field will get a default IS_IN_DB validator as well as a multi-select widget showing the names of the categories (this is enabled by virtue of the "format" argument in the category
table definition, which is set to the "name" field).
A final option is to set up a full many-to-many schema, which requires a third table. However, this will complicate setting up form entry, as there is no built-in method to create a new_product entry form with a multi-select for the many-to-many relationship.
Upvotes: 2