Auth with migrate=False

195 views
Skip to first unread message

Paolo valleri

unread,
Jan 15, 2013, 5:07:49 AM1/15/13
to web...@googlegroups.com
Hi all, I tried something odd.
I pulled a fresh copy of my code from git and I connected the app to an already 'working' database. 'working' in the meaning that both tables and data are already in the database. In web2py this approach fails, because at the first run it tries to create all the tables, and the db raises an exception like 'table already exist'.
In order to fix that I thought that migrate=False would help, however it fails again. due to Auth that tries to create the tables. Ticket:
Traceback (most recent call last):
 
File "/home/pvalleri/src/web2py/gluon/restricted.py", line 212, in restricted
   
exec ccode in environment
 
File "/home/pvalleri/src/web2py/applications/vtraffic/controllers/default.py", line 6, in <module>
   
start = db.record.with_alias('start_point')
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7221, in __getattr__
   
return self.lazy_define_table(tablename,*fields,**args)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7174, in lazy_define_table
    table
= table_class(self, tablename, *fields, **args)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7594, in __init__
    field
.requires = sqlhtml_validators(field)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 6338, in sqlhtml_validators
    referenced
= db[field_type[10:]]
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7215, in __getitem__
   
return self.__getattr__(str(key))
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7221, in __getattr__
   
return self.lazy_define_table(tablename,*fields,**args)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7177, in lazy_define_table
    table
._create_references() # must follow above line to handle self references
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7663, in _create_references
    rtable
= db[rtablename]
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7215, in __getitem__
   
return self.__getattr__(str(key))
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7221, in __getattr__
   
return self.lazy_define_table(tablename,*fields,**args)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 7189, in lazy_define_table
    polymodel
=polymodel)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 935, in create_table
   
self.create_sequence_and_triggers(query,table)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 2483, in create_sequence_and_triggers
   
self.execute(query)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 1709, in execute
   
return self.log_execute(*a, **b)
 
File "/home/pvalleri/src/web2py/gluon/dal.py", line 1703, in log_execute
    ret
= self.cursor.execute(*a, **b)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/dbapi.py", line 246, in _fn
   
return fn(self, *args, **kwargs)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/dbapi.py", line 317, in execute
   
self._execute(operation, args)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/dbapi.py", line 322, in _execute
   
self.cursor.execute(new_query, *new_args)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/interface.py", line 399, in execute
   
self._stmt.execute(*args, **kwargs)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/interface.py", line 169, in execute
   
self._row_desc, cmd = self.c.bind(self._portal_name, self._statement_name, args, self._parse_row_desc, kwargs.get("stream"))
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/protocol.py", line 943, in _fn
   
return fn(self, *args, **kwargs)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/protocol.py", line 1142, in bind
   
return reader.handle_messages()
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/protocol.py", line 911, in handle_messages
    retval
= handler(msg, *args, **kwargs)
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/protocol.py", line 1181, in _bind_nodata
    reader
.handle_messages()
 
File "/home/pvalleri/src/web2py/gluon/contrib/pg8000/protocol.py", line 916, in handle_messages
   
raise exc
ProgrammingError: ('ERROR', '42P07', 'relation "auth_user" already exists')

What I understood is that web2py with migrate=False doesn't create tables at all, skipping this step to improve performance.
is it correct?

Paolo

Niphlod

unread,
Jan 15, 2013, 5:38:49 AM1/15/13
to web...@googlegroups.com
migrate=False is on the db or on Auth define_table() call ?
_fn
   
return fn(self, *args<span style="color: #660;" class="styled-by...
Mostra originale

Paolo valleri

unread,
Jan 15, 2013, 7:35:14 AM1/15/13
to web...@googlegroups.com
is on the db definition. 
db = DAL('postgres://web2py:web2py@localhost:5432/traffic', 
migrate=False,
lazy_tables=True,
)

Paolo

Anthony

unread,
Jan 15, 2013, 7:58:47 AM1/15/13
to web...@googlegroups.com
DAL(..., migrate=False) does not completely turn off migrations but merely sets the default migrate value for each table to False if it is not set explicitly. The auth.define_tables() method, however, explicitly sets migrate to True for each Auth table unless otherwise specified, so you would have to do auth.define_tables(..., migrate=False). Another option is to completely disable all migrations, regardless of individual table settings, via:

DAL(..., migrate_enabled=False)

Anthony

paolo....@gmail.com

unread,
Jan 15, 2013, 8:11:48 AM1/15/13
to web...@googlegroups.com
Thanks for clarifying it. 
So that, to speed up web2py, we must use migrate_enabled=False instead of migrate=False at DAL definition. Otherwise for all the auth_* tables, web2py will access the disk to verify if the relative file in databases/hash_tablename.table exists and is updated, right?
If what I have said is correct I would suggest to update the book, http://web2py.com/books/default/chapter/29/13#Efficiency-tricks
changing migrate=False with migrate_enabled=False

Paolo


2013/1/15 Anthony <abas...@gmail.com>
--
 
 
 



--
 Paolo

Niphlod

unread,
Jan 15, 2013, 8:15:52 AM1/15/13
to web...@googlegroups.com
I'd rather specify also that auth.define_tables(migrate=False) is the way to go to turn migrations off of all the auth_* tables

paolo....@gmail.com

unread,
Jan 15, 2013, 8:32:47 AM1/15/13
to web...@googlegroups.com
One or an other is ok, they lead to the same thing! I am adding them to my project :)
However, after I first test, i could see any difference, I will investigate more asap


2013/1/15 Niphlod <nip...@gmail.com>

--
 
 
 



--
 Paolo

Anthony

unread,
Jan 15, 2013, 9:10:32 AM1/15/13
to web...@googlegroups.com
Good point. Even better, use lazy_tables. You should also compile the app.

Paolo valleri

unread,
Jan 15, 2013, 9:27:55 AM1/15/13
to web...@googlegroups.com
I am using lazy_tables=True at DAL definition, actually I don't know how to enable lazy_table for auth. Does it exist?
As I can see, auth.define_tables doesn't take any lazy_table parameter, moreover in my code I have a few lines of auth.settings.* which needs auth. 
To customize my own tables without forcing their creation I am using the on_define function, as shown in the example below:
db.define_table('answers',
   
Field('question_id', db.questions),
   
Field('route_id', db.route),
   
Field('description', 'text' ),
       auth.signature,
    on_define = lambda table: [
        table
.route_id.set_attributes(readable = False, writable = False),
   
]
)

Paolo

Anthony

unread,
Jan 15, 2013, 11:35:35 AM1/15/13
to web...@googlegroups.com
On Tuesday, January 15, 2013 9:27:55 AM UTC-5, Paolo valleri wrote:
I am using lazy_tables=True at DAL definition, actually I don't know how to enable lazy_table for auth. Does it exist?

Setting lazy_tables at the DAL definition affects all tables, including the Auth tables.
 
As I can see, auth.define_tables doesn't take any lazy_table parameter, moreover in my code I have a few lines of auth.settings.* which needs auth. 

If you have code that directly refers to an Auth table after it has been defined lazily, then the table will be fully defined. In that case, you could move that code to the action that actually needs it (e.g., the user() action). Perhaps we should add an _on_define attribute to tables so it is possible to add an on_define function after the initial lazy table definition.

Anthony

paolo....@gmail.com

unread,
Jan 15, 2013, 12:42:05 PM1/15/13
to web...@googlegroups.com
Hi Anthony, I agree with you. It would be nice to have such a on_define function, this will not only optimize the code but also makes the code more readable. I prefer the function rather than distributing in several controllers the code that forces the definition of Auth


2013/1/15 Anthony <abas...@gmail.com>

Anthony

--
 
 
 



--
 Paolo
Message has been deleted

Massimo Di Pierro

unread,
Jan 15, 2013, 2:48:45 PM1/15/13
to web...@googlegroups.com
You can do

db._LAZY_TABLES['yourtablename'][2]['on_define'] = ....

Not as nice as what Anthony is proposing but works the same. We can change it but it would require treating one argument of define_table, on_define_ differently than all the other ones.

Anthony

unread,
Jan 15, 2013, 3:55:02 PM1/15/13
to web...@googlegroups.com
On Tuesday, January 15, 2013 2:48:45 PM UTC-5, Massimo Di Pierro wrote:
You can do

db._LAZY_TABLES['yourtablename'][2]['on_define'] = ....

Good one -- didn't think of that. :-)

Anthony 

paolo....@gmail.com

unread,
Jan 16, 2013, 2:59:27 AM1/16/13
to web...@googlegroups.com
Hi Massimo, personally I don't like this:

db._LAZY_TABLES['yourtablename'][2]['on_define'] = ....
it is neither easy to remember nor easy to understand what it dows. Something more friendly would be better from my point of view, If adding an on_define could create misunderstanding since the parameter is different from the 'common' on_define, we could use an other totally fresh name, i.e., auth.set_settings, auth.customize and so on to do the same thing.

--
 Paolo

Massimo Di Pierro

unread,
Jan 16, 2013, 10:34:42 PM1/16/13
to web...@googlegroups.com
Me neither. Let's think of a solution on web2py_developers.

paolo....@gmail.com

unread,
Jan 25, 2013, 10:55:53 AM1/25/13
to web...@googlegroups.com
Hi Massimo, just wondering if you have found something better for this.
Paolo


2013/1/17 Massimo Di Pierro <massimo....@gmail.com>
--
 
 
 



--
 Paolo

Massimo Di Pierro

unread,
Jan 30, 2013, 10:19:23 AM1/30/13
to web...@googlegroups.com
Not really. How about:

def set_on_delete(db, tablename, f):
    db._LAZY_TABLES[tablename][2]['on_define'] = f

The problem is that we cannot use the notation db.table.on_delete = f since db.table will cause the table to be instantiated and that what lazy tables are trying to postpone.
Reply all
Reply to author
Forward
0 new messages