Total control over models


Total control over your models

http://aprenda-web2py.blogspot.com/2011/04/total-control-over-your-models.html
Every single web2py application that uses database, has its own models dir.

This directory is particularly important due to some characteristics:

  1. models directory files ares executed in alphabetical order;
  2. Your application’s database tables definitions stay in it;
  3. Objects defined by these files become available on your app’s global scope. They can be accessed by controllers and views.

I warn you to pay attention to the first one: files are executed in alphabetical order.

Some newbies have dificulties with that, and tend to think this is strange. I did it, until I concluded this is the most intuitive way to things work. It gives me freedom to organize my app.

However, to avoid some mistakes this way can bring to your app, we need to adopt a clear and fool proof convetion to name models files. 

I use this simple and efficient structure:

  1. models/0_db.py
  2. models/1_menu.py
  3. models/5_models.py
  4. models/5_validators.py

I rename the automatically created db.py file to 0_db.py. So, I guarantee all basic definitions are executed before anything else. The DAL object, who provides all data access funcionalities, is created in this script.

I also rename menu.py to 1_menu.py forcing all menu definitions to be executed after DAL object instantiation.

With these modified names, I’m sure that all the code I’ll develop will be executed after the scaffolding app web2py generated to me.

From that point I write models/5_models.py with my table definitions. Nothing butdb.define_table() commands.

Validators are written in models/5_validators.py. But, why separated from model definitions? First, because web2py recommends you don’t mix validators with db.define_table(). Second, because at this point I’m certain all tables are already created and all cross references between them will work with no need to adjust definition sequences. Sometimes it messes my scripts.

When I have many tables, I can separate them in various scripts, i.e,5_models_accounts.py5_models_finances.py, etc. And, the same way, their validators.

Here, your creativity can fly, but remeber some principles:

Explicit is better than implicit. 
Simple is better than complex.
Flat is better than nested.
Readabilty counts. 
In the face of ambiguity, refuse the temptation to guess.

0

0
 

how to generate a many-to-many-relationship FORM in web2py?

python – how to generate a many-to-many-relationship FORM in web2py? – Stack Overflow

 

Do I need a custom validator? Do I need a custom widget?

If this helps to clear the problem, the relationship is between member and language where a member can have multiple languages and a language is spoken by multiple members.

I would like to add a multi-select box in the “add member” form (that I generate using SQLFORM).

Thanks :)

link|improve this question
 
   
feedback

2 Answers

It depends and I suggest you take this on the web2py mailin list. One way to do it is

db.table.field.requires=IS_IN_DB(db,'othertable.id','%(otherfield)',multiple=True)
link|improve this answer
 
   
feedback

Another way to do this:

db.define_table( 'make', Field( 'name' ) )

db.define_table( 'model',
    Field( 'name' ),
    Field( 'make', db.make, requires = IS_IN_DB( db, 'make.id', '%(name)' ) ) )
link|improve this answer

 

0

0
 

Modify CRUD Form in web2py before sending to view

python – Modify CRUD Form in web2py before sending to view – Stack Overflow

 

I cannot seem to find a way to modify a form that has been created via:

from gluon.tools import Crud
crud = Crud(globals(), db)

form = crud.create(db.table_name)

Since I am using foreign keys in my table, the auto-generated form only allows an integer (which represents the foreign primary key), but what I want to be able to do is enter whatever data type the foreign data field requires (rather than just the identifier). Is there an easy way to tell the create() function to use the foreign table’s data type rather than the primary table’s data type (which is the auto-incrementing primary key)?

link|improve this question


42% accept rate
feedback

1 Answer

You can use database validators to it.

It will show a select box with the values from foreign table: (from http://web2py.com/book/default/chapter/07?search=requires#Database-Validators):

IS_IN_DB

Consider the following tables and requirement:

db.define_table('person', Field('name', unique=True))
db.define_table('dog', Field('name'), Field('owner', db.person)
db.dog.owner.requires = IS_IN_DB(db, 'person.id', '%(name)s',
                                 zero=T('choose one'))

It is enforced at the level of dog INSERT/UPDATE/DELETE forms. It requires that a dog.owner be a valid id in the field person.id in the database db. Because of this validator, the dog.owner field is represented as a dropbox. The third argument of the validator is a string that describes the elements in the dropbox. In the example you want to see the person %(name)s instead of the person %(id)s. %(…)s is replaced by the value of the field in brackets for each record.

The zero option works very much like for the IS_IN_SET validator.

If you want the field validated, but you do not want a dropbox, you must put the validator in a list.

db.dog.owner.requires = [IS_IN_DB(db, 'person.id', '%(name)s')]

The first argument of the validator can be a database connection or a DAL Set, as in IS_NOT_IN_DB.

Occasionally you want the drop-box (so you do not want to use the list syntax above) yet you want to use additional validators. For this purpose the IS_IN_DB validator takes an extra argument _and that can point to a list of other validators applied if the validated value passes the IS_IN_DB validation. For example to validate all dog owners in db that are not in a subset:

subset=db(db.person.id>100)
db.dog.owner.requires = IS_IN_DB(db, 'person.id', '%(name)s',
                                 _and=IS_NOT_IN_DB(subset,'person.id'))

IS_IN_DB and Tagging

The IS_IN_DB validator has an optional attribute multiple=False. If set to True multiple values can be stored in one field. This field should be of type list:reference as discussed in Chapter 6. An explicit example of tagging is discussed there. multiple references are handled automatically in create and update forms, but they are transparent to the DAL. We strongly suggest using the jQuery multiselect plugin to render multiple fields.

link|improve this answer
If I choose to not use the dropbox, is there a way to make the text field auto-insert the new entry into the foreign table? – blastthisinferno Aug 19 ’10 at 16:24

 

0

0