Algo realmente extraño sucedió al eliminar todas las tablas en web2py

Quiero eliminar todas las tablas en la base de datos. db. Todo lo que hago es iterar db.tables y suéltalos uno por uno. Sin embargo, algunas tablas se ignoran y, por lo tanto, no se eliminan. Entonces cambié drop a truncate, cada tabla se trunca. Entonces, ¿qué tiene de malo drop?

Aquí están los códigos:

controladores/admin.py:

def olddo_remove():
    response.view = 'admin/do_remove.html'
    l = []
    k = []
    for table_name in db.tables:
        l.append(table_name)
        db[table_name].drop()
        #db[table_name].truncate()
    return locals()

def do_remove():
    l = []
    k = []
    for table_name in db.tables:
        l.append(table_name)
    for table_name in l:
        k.append(table_name)
        db[table_name].drop()
    return locals()

vistas/admin/do_remove.html:

{{=l}}<br />{{=k}}

Cuando visito admin/olddo_remove, obtengo

['auth_user', 'auth_membership', 'auth_event', 'client', 'data']
[] 

Cuando visito admin/do_remove, obtengo

['auth_user', 'auth_group', 'auth_membership', 'auth_permission', 'auth_event', 'auth_cas', 'client', 'product', 'data']
['auth_user', 'auth_group', 'auth_membership', 'auth_permission', 'auth_event', 'auth_cas', 'client', 'product', 'data'] 

Si cambio el drop a truncate en olddo_remove, la salida será

['auth_user', 'auth_group', 'auth_membership', 'auth_permission', 'auth_event', 'auth_cas', 'client', 'product', 'data']
[] 

¿Por qué? ¿Qué ocurre?


Esto va LOCA!!

def test():
    response.view = 'admin/do_remove.html'
    l = db.tables
    k = []
    for table_name in l:
        k.append(table_name)
        db[table_name].drop()
    return locals()

Salida:

['auth_group', 'auth_permission', 'auth_cas', 'product']
['auth_user', 'auth_membership', 'auth_event', 'client', 'data'] 

Y solo se descartaron las tablas de la segunda línea.

preguntado el 28 de julio de 12 a las 10:07

1 Respuestas

Este es un problema de Python. db.tables es un objeto de lista (en realidad, es un objeto SQLCallableList especial, que hereda de la lista). db[table_name].drop() no solo elimina la tabla table_name de la base de datos, sino que también elimina table_name de la db.tables lista. Entonces, en el bucle for, está iterando sobre una lista y mutando esa lista (es decir, eliminando elementos de ella) a medida que itera. Esta es la razón por la que solo obtienes todas las demás mesas. En el ejemplo que funciona, primero está copiando la lista y luego iterando sobre la copia (que no se muta en el ciclo), por lo que funciona como se esperaba. El truncamiento funciona incluso cuando se itera sobre db.tables directamente porque el truncamiento no elimina las tablas (de la base de datos o de db.tables).

Tenga en cuenta, como se mencionó anteriormente, db.tables es una SQLCallableList. Eso significa que db.tables() devuelve una copia del db.tables lista, por lo que en su lugar puede iterar sobre la copia:

for table_name in db.tables():
    db[table_name].drop()

El .drop() eliminará table_name de db.tables pero no lo quitará de la db.tables() copia sobre la que itera el bucle for, por lo que todo debería funcionar como se esperaba.

Respondido 30 Jul 12, 16:07

¿Por qué sería eso un error? web2py está haciendo algo sensato: cuando elimina una tabla de la base de datos, también la elimina de db.tables. En Python, si recorre una lista y luego muta esa lista dentro del ciclo, obtiene este comportamiento. Así es como funciona Python, y creo que también es sensato. No veo un error aquí. Solo tienes que saber cómo funciona Python. - Antonio

Tenga en cuenta que actualicé la respuesta proporcionando una alternativa usando db.tables(). - Antonio

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.