[pyar] Campo Primario Web2py

Mariano Mara mariano.mara en gmail.com
Sab Feb 5 23:09:29 ART 2011


On 05.02.11 19:54, Roberto Perdomo wrote:
>    A mi modo de ver las cosas, mientras más validaciones tenga un
>    sistemas, más robusto será, lo correcto sería, tener validaciones en el
>    cliente, en el servidor y en la base de datos, solo así nos podremos
>    asegurar de que la data almacenada en esta última es la correcta.
> 
>    Si es independiente o no la base de datos  no es problema, porque de
>    ello se encarga el modelo en Web2py.
> 
>    Es por ello que el unique, me define a nivel de bases de datos (cuando
>    es creada) que no debe ser un campo repetido y el IS_NOT_IN_DB lo hace
>    como dijo el compañero Mariano Reingart, lo hace a nivel de
>    controlador/vista.
> 
>    Mejor tener un sistema blindado de validaciones que tener un sistema
>    con una sola validación, alli si te creo que puedan existir campos
>    vacios, datos duplicados y muchos otros datos indeseados en la BD
> 

En realidad no creo que tener un sistema blindado como vos decís sea
a veces lo más práctico. Vos tenes que poner la validación en el lugar que tenga más
sentido (que te asegure que ese control siempre anda con la menor cantidad de
código posible).
Tomando el ejemplo que mencionás de IS_NOT_IN_DB: tu base para que
inserción de registro que hagas está haciendo dos cosas (me gusta pensar
que hay bases lo suficientemente inteligentes para anular uno de los dos
pasos al detectar que son redundantes):
 * agregando una clausula "not in" en el criterio del query
 * cuando efectivamente se inserta, revisando que la columna con un
   constraint unique no esté repetida
Quiero dejar constancia que la verdad es que no tengo ni idea que hace
el IS_NOT_IN_DB de web2py: muy posiblemente también se de cuenta de la
redundancia y no aplique el filtro. Lo mío -como dije anteriormente- es
framework agnostic, son más bien consideraciones generales.

Poniendo la misma validación en varias capas del sistema te
exponés a las siguientes situaciones:
1- estás trabajando de más.
2- corrés el riesgo que alguna de las validaciones quede desactualizada
(por ejemplo por un cambio en las reglas del negocio).
3- haciendo que todo tarde más (en un sistema con poca concurrencia por
ahí esto no te importa pero si tenés más de 10000 usuarios intentando
insertar al mismo tiempo, ahí puede que sea interesante considerarlo).

Claro que todo no es blanco o negro y llegado el momento antes de poner
una validación tenes que hacer la relación costo beneficio de lo que
estás por hacer:
a- ponés solo un unique constraint pero en la rutina de inserción de
datos tener que agregar más código para atajar la excepción.
b- usando IS_NOT_IN_DB el framework automaticamente te entrega un
hermoso drop-down que no tuviste que codear vos 

ahí podés decir que te bancas la doble validación porque te ahorraste
tiempo de desarrollo si no lo hubieras hecho. Y llegado el caso que
estemos hablando de una tabla crítica del sistema y estés en la duda,
siempre podés hacer un poco de stress (con alguna herramienta simple
tipo JMeter por ejemplo) y comparar cuanto te cuesta tener más de una
validación, tener una sola o no tener ninguna.

Mariano

>    El 4 de febrero de 2011 16:08, Mariano Mara <[1]mariano.mara en gmail.com>
>    escribió:
> 
>    On 04.02.11 15:25, Roberto Perdomo wrote:
>    > a mi me quedó asi definitivamente y funciona al 100% con Postgres:
>    >
>    > db.tipo_nomina.nomina.requires= [IS_NOT_EMPTY(error_message='Ha
>    > introducido un valor vacío'),
>    >                                  IS_NOT_IN_DB(db,
>    'tipo_nomina.nomina',
>    >                                               error_message = 'Este
>    > registro ya se encuentra procesado'),
>    >                                  IS_LENGTH(maxsize=40, minsize=5,
>    > error_message='Introduzca entre %(min)g y %(max)g caracteres')
>    >                                  ]
> 
>      ¿Pero estás reforzando la regla a nivel de base de datos con un
>      constraint unique o primary key?
>      Hace mucho que no toco web2py así que mi consejo es "framework
>      agnostic" (capaz que ya lo tuviste en cuenta a todo esto pero
>      permitime dejar constancia por si le sirve a alguien más):
>      las reglas que se puedan reforzar a nivel de base de datos
>      (clave primaria y foranea, nulidad, algunas validaciones que te
>      permita
>      el motor en una instrucción "check constraint", etc) *tienen* que
>      estar
>      en la base.
>      Desconozco el alcance de tu proyecto o cuanto esfuerzo le querés
>      poner
>      pero sea cual sea vos no podés asegurar que tu frontend va a ser la
>      única vía por la cual alguien va a acceder a los datos para siempre.
>      Algunos ejemplos simples:
>      * mañana hay que hacer una inserción masiva de registros (pongamos
>      que
>       con un csv)
>      * mañana se te da por agregar una API (tan social hoy en día) para
>      que
>       otras aplicaciones se puedan conectar y modificar tus datos vía
>       servicios web
>      * mañana vos te vas, viene otro al que no le gusta web2py y convence
>      a
>       tu jefe que <nuevo lenguaje en boga> es lo mejor y reescribe toda
>      la
>       aplicación en ese nuevo lenguaje.
>      Cualquiera de esos escenarios van a pasar tus restricciones a nivel
>      controlador/vista como arroyo al tranco y vas a terminar con una
>      base
>      llena de duplicados, registros huerfanos y nulos donde no debería
>      ser
>      posible.
>      Entiendo que a veces ponerse a trabajar en esas cosas en la base es
>      una
>      molestia:
>      * porque tenes un chequeo en el controlador y otra vez en la base
>       (aunque no es necesario que así sea)
>      * porque es más rápido insertar en una tabla sin restricciones que
>      en
>       una donde tenés algún control (una unique o primary hace un full
>      scan
>       del índice)
>      * porque no todos los motores de bases de datos soportan las mismas
>       reglas y entonces a veces tu aplicación no es tan "database
>       independent" como te gustaría.
>      pero teniendo las reglas a nivel de base, dormís tranquilo sabiendo
>      que
>      muchos escenarios donde pueden haber problemas no te van a suceder.
>      De
>      última es más fácil aclarar/arreglar un "duplicate index on table"
>      que
>      ponerse a borrar registros en cascadas dentro de la base. Como valor
>      agregado, la base de datos entiende mejor tu modelo y sabe cual es
>      la
>      mejor forma de ejecutar un query que le pidas.
>      Como dicen a veces "las aplicaciones pasan pero los datos quedan".
> 
>    >
>    > El 04/02/11, Mariano Reingart <[2]reingart en gmail.com> escribió:
>    > > Cuando son varios validadores, van en una lista:
>    > >
>    > > db.nadadores.fecnac.requires = [ IS_DATE(error_message='Formato
>    > > erroneo? (AAA-MM-DD)'),
>    > >
>    > > IS_NOT_EMPTY(error_message='Campo Obligatorio'), ]
>    > >
>    > > Sds
>    > >
>    > >
> 
>    > > 2011/2/4 nicolás rosbaco <[3]antiyanki en gmail.com>:
>    > >> Hola, lo probé y me pasa esto:
>    > >>
>    > >> 2011/2/3 Roberto Perdomo <[4]robertop23 en gmail.com>
>    > >>>
>    > >>> 2011/2/3 nicolás rosbaco <[5]antiyanki en gmail.com>
>    > >>>>
>    > >>>> OK. entonces: unique, evita la inserción de tuplas en las tablas
>    (si la
>    > >>>> clave esta repetida)... y pasa por cuenta del programador evitar
>    que
>    > >>>> ello
>    > >>>> ocurra (o atrapar la excepción supongo yo)
>    > >>>>
>    > >>>> con IS_NOT_IN_DB las verificaciones se hacen antes de modificar
>    la
>    > >>>> tabla... pero la tabla no es creada con la restricción referida
>    ¿está
>    > >>>> bien?
>    > >>>>
>    > >>>> Por otro lado: como hago (cuando creo la tabla) si quiero
>    incluir más de
>    > >>>> un requires???
>    > >>>
>    > >>> Si necesitas mas de uno lo haces asi:
>    > >>>
>    > >>> db.define_table('tipo_nomina'
>    > >>> ,
>    > >>>       SQLField('nomina', type='string', length=40, notnull=False,
>    > >>> unique=True, required=True))
>    > >>>
>    > >>>
>    > >>>
>    > >>> db.tipo_nomina.nomina.requires= IS_IN_DB(db,
>    db.tipo_nomina.nomina,
>    > >>> error_message='Ha introducido un valor vacío o registrado')
>    > >>>
>    > >>>
>    > >>> db.tipo_nomina.nomina.requires = IS_LENGTH(maxsize=40, minsize=5,
>    > >>> error_message='Introduzca entre %(min)g y %(max)g caracteres')
>    > >>>
>    > >>
>    > >> Yo tengo las siguientes condiciones:
>    > >> db.nadadores.fecnac.requires = IS_DATE(error_message='Formato
>    erroneo?
>    > >> (AAA-MM-DD)')
>    > >> db.nadadores.fecnac.requires = IS_NOT_EMPTY(error_message='Campo
>    > >> Obligatorio')
>    > >>
>    > >> si ingreso en el campo fecha cualquier verdura la tupla se agrega
>    (después
>    > >> claro da error al intentar listar la tabla) a la tabla!
>    > >>
>    > >> Si dejo vacío el campo chilla el validador! por lo tanto: el
>    último
>    > >> requires
>    > >> esta siendo considerado....
>    > >>
>    > >> Ahora (acá lo curioso) si borro el último requires y luego ingreso
>    > >> cualquier
>    > >> verdura en el campo fecha chilla!...
>    > >>
>    > >> Me da a pensar que un requires anula el anterior.... ¿puede ser?
>    > >>
>    > >>>
>    > >>> db.tipo_nomina.nomina.requires =
>    > >>> IS_MATCH('^[a-zA-ZáéíóúÁÉÍÓÚ\s]+$',error_message='Introduzca solo
>    > >>> letras')
>    > >>>>
>    > >>>> Bueno gente, esto esta re bueno. Muchas gracias
>    > >>>>
>    > >>>>
>    > >>>> El 3 de febrero de 2011 19:49, Mariano Reingart
>    <[6]reingart en gmail.com>
>    > >>>> escribió:
>    > >>>>>
>    > >>>>> Las restricciones primarykey, unique y notnull  se aplican a
>    nivel de
>    > >>>>> datos, web2py no las verifica, simplemente crea las tablas con
>    esas
>    > >>>>> condiciones, y el servidor de base de datos debería hacer el
>    resto
>    > >>>>> (por lo que los conectores lanzan excepciones).
>    > >>>>>
>    > >>>>> Los validadores (IS_NOT_IN_DB, IS_IN_DB, IS_NOT_EMPTY)
>    funcionan a
>    > >>>>> nivel de los controladores/vistas, son verificados antes de
>    modificar
>    > >>>>> la base de datos, cuando el usuario utiliza un formulario (y
>    muestran
>    > >>>>> un mensaje de error en la pantalla, con la posibilidad de
>    corregir el
>    > >>>>> formulario).
>    > >>>>>
>    > >>>>> En el libro está explicado en detalle:
>    > >>>>>
>    > >>>>>
>    > >>>>>
>    [7]http://www.latinuxpress.com/books/drafts/web2py/caps/cap6.html#repre
>    sentacion-de-registros
>    > >>>>>
>    > >>>>> En este caso, con IS_NOT_IN_DB no aceptaría el formulario
>    mostrando un
>    > >>>>> error al usuario si esta duplicado algún valor.
>    > >>>>>
>    > >>>>> Sds
>    > >>>>>
> 
>    > >>>>> 2011/2/3 nicolás rosbaco <[8]antiyanki en gmail.com>:
>    > >>>>> > me faltó decir que estoy trabajando con web2py
>    > >>>>> >
>    > >>>>> > El 3 de febrero de 2011 19:30, nicolás rosbaco
>    <[9]antiyanki en gmail.com>
>    > >>>>> > escribió:
>    > >>>>> >>
>    > >>>>> >> Hola, mira no tengo la solución... pero si me paso algo
>    parecido y
>    > >>>>> >> de
>    > >>>>> >> pronto por acá puedo llegar a saber que pasa.
>    > >>>>> >>
>    > >>>>> >> En mi caso el unique tampoco anduvo (¿ignoro por que??) pero
>    utilicé
>    > >>>>> >> lo
>    > >>>>> >> siguiente:
>    > >>>>> >>
>    > >>>>> >> db.nadadores.email.requires = IS_NOT_IN_DB(db,
>    'nadadores.email',
>    > >>>>> >> error_message='Dirección de mail duplicada. Ya existe un
>    usuario
>    > >>>>> >> registrado
>    > >>>>> >> con esta dirección de mail')
>    > >>>>> >>
>    > >>>>> >> La verdad que me gustaría saber para que sirve el unique, ya
>    que
>    > >>>>> >> suponía
>    > >>>>> >> lo mismo que vos
>    > >>>>> >>
>    > >>>>> >>
>    > >>>>> >> 2011/2/3 Roberto Perdomo <[10]robertop23 en gmail.com>
>    > >>>>> >>>
>    > >>>>> >>> Buenas tardes,
>    > >>>>> >>>
>    > >>>>> >>> Alguien de casualidad tiene conocimiento en cuanto a como
>    definir
>    > >>>>> >>> un
>    > >>>>> >>> campo primario adicional en una tabla.
>    > >>>>> >>>
>    > >>>>> >>> Tengo por ejemplo una tabla:
>    > >>>>> >>>
>    > >>>>> >>> db.define_table('tipo_nomina',
>    > >>>>> >>>       SQLField('nomina', type='string', length=40,
>    notnull=True,
>    > >>>>> >>> required=True, unique=True)
>    > >>>>> >>>       )
>    > >>>>> >>>
>    > >>>>> >>> Donde unique=True supuestamente debería funcionar y hacer
>    que no se
>    > >>>>> >>> permitan valores repetidos para el campo nomina, pero, al
>    añadir un
>    > >>>>> >>> valor
>    > >>>>> >>> repetido resulta el siguiente error:
>    > >>>>> >>>
>    > >>>>> >>>
>    > >>>>> >>> IntegrityError: duplicate key value violates unique
>    constraint
>    > >>>>> >>> "tipo_nomina_nomina_key"
>    > >>>>> >>>
>    > >>>>> >>> Investigue un poco y dicen que es un error de la Base de
>    Datos, en
>    > >>>>> >>> mi
>    > >>>>> >>> caso es Postgres. Entonces Web2py no es capaz de manejar o
>    mejor
>    > >>>>> >>> dicho,
>    > >>>>> >>> generar un error para cuando se esta insertando un valor
>    repetido
>    > >>>>> >>> en
>    > >>>>> >>> un
>    > >>>>> >>> campo?
>    > >>>>> >>>
>    > >>>>> >>> Intente con primarykey = ['nomina'], pero fue infructuoso.
>    > >>>>> >>>
>    > >>>>> >>> lo que quisiera seria realmente poder definir un campo
>    primario
>    > >>>>> >>> para
>    > >>>>> >>> evitar valores repetidos, pero no encuentro la manera
>    adecuada para
>    > >>>>> >>> ello.
>    > >>>>> >>>
>    > >>>>> >>> PD: los formularios son generado utilizando SQLFORM y CRUD
>    > >>>>> >>>
>    > >>>>> >>> Gracias de antemano
>    > >>>>> >>>
>    > >>>>> >>>
>    > >>>>> >>>
>    > >>>>> >>>
>    > >>>>> >>> _______________________________________________
>    > >>>>
> 
>    > >>>> --
>    > >>>> "En un país colonial las oligarquías son las dueñas de los
>    diccionarios"
>    > >>>> (John William Cooke)
>    > >>>>
>    _______________________________________________
>    pyar mailing list [11]pyar en python.org.ar
>    [12]http://listas.python.org.ar/listinfo/pyar
>    PyAr - Python Argentina - Sitio web: [13]http://www.python.org.ar/
> 
> References
> 
>    1. mailto:mariano.mara en gmail.com
>    2. mailto:reingart en gmail.com
>    3. mailto:antiyanki en gmail.com
>    4. mailto:robertop23 en gmail.com
>    5. mailto:antiyanki en gmail.com
>    6. mailto:reingart en gmail.com
>    7. http://www.latinuxpress.com/books/drafts/web2py/caps/cap6.html#representacion-de-registros
>    8. mailto:antiyanki en gmail.com
>    9. mailto:antiyanki en gmail.com
>   10. mailto:robertop23 en gmail.com
>   11. mailto:pyar en python.org.ar
>   12. http://listas.python.org.ar/listinfo/pyar
>   13. http://www.python.org.ar/

> _______________________________________________
> pyar mailing list pyar en python.org.ar
> http://listas.python.org.ar/listinfo/pyar
> 
> PyAr - Python Argentina - Sitio web: http://www.python.org.ar/




More information about the pyar mailing list