Los modelos Django / SQLAlchemy están hinchados! ¿Algún modelo de DB realmente python por ahí?

Haz las cosas lo más simples posible, pero no más simples.

¿Podemos encontrar las soluciones que corrigen el mundo de la base de datos de Python?

Actualización: Alex Martelli ha escrito un prototipo ‘lustdb’ . Si conoce alguna biblioteca de bases de datos de alto nivel, algo liviana, con múltiples backends que podamos incluir en la syntax de la miel de azúcar.

from someAmazingDB import * #we imported a smart model class and db object which talk to database adapter/s class Task (model): title = '' done = False #native types not a custom object we have to think about! db.taskList = [] #or db.taskList = expandableTypeCollection(Task) #not sure what this syntax would be db['taskList'].append(Task(title='Beat old sql interfaces',done=False)) db.taskList.append(Task('Illustrate different syntax modes',True)) # ok maybe we should just use kwargs #at this point it should be autosaved to a default db option #by default we should be able to reload the console and access the default db: >> from someAmazingDB import * >> print 'Done tasks:' >> for task in db.taskList: >> if task.done: >> print task.title 'Illustrate different syntax modes' 

Soy fan de Python , webPy y Cherry Py, y de KISS en general.

Estamos hablando de la traducción automática de tipo Python a SQL o NoSQL. ¡No tenemos que ser totalmente compatibles con SQL! Sólo un subconjunto escalable o ignorarlo!

Re: el modelo cambia, está bien preguntar al desarrollador cuándo intenta cambiarlo o tener un conjunto de valores predeterminados razonables.

Aquí está el desafío: el código anterior debe funcionar con muy poca modificación o pensamiento requerido. ¿Por qué debemos aceptar el compromiso cuando sabemos mejor?

Es 2010, deberíamos poder codificar bases de datos escalables y simples en nuestro sueño.

Si crees que esto es importante, por favor vota!

Lo que solicites no se puede hacer en Python 2. Lo que sea , por una razón muy específica. Quieres escribir

 class Task(model): title = '' isDone = False 

En Python 2. cualquier cosa , cualquiera model sea ​​el model , esto nunca puede permitirle predecir ningún “orden” para los dos campos, porque la semántica de una statement de class es:

  1. Ejecutar el cuerpo, preparando así un dict
  2. Localiza la metaclase y ejecuta sus métodos especiales.

Cualquiera que sea la metaclase, el paso 1 ha destruido cualquier previsibilidad del orden de los campos.

Por lo tanto, su uso deseado de los parámetros posicionales, en el fragmento de código:

 Task('Illustrate different syntax modes', True) 

no se pueden asociar los valores de los argumentos con los diversos campos del modelo. (Tratar de adivinar por asociación de tipo (esperando que no haya dos campos que tengan el mismo tipo) sería aún más horriblemente anti-tónico que su deseo expresado de usar db.tasklist y db['tasklist'] indistintamente e indistintamente).

Uno de los cambios incompatibles con versiones anteriores en Python 3 se introdujo específicamente para tratar situaciones de esta clase. En Python 3, una metaclase personalizada puede definir una función __prepare__ que se ejecuta antes del “paso 1” en la lista simplificada anterior, y esto le permite tener más control sobre el cuerpo de la clase. Específicamente, citando PEP 3115 …:

__prepare__ devuelve un objeto similar a un diccionario que se utiliza para almacenar las definiciones de los miembros de la clase durante la evaluación del cuerpo de la clase. En otras palabras, el cuerpo de la clase se evalúa como un bloque de función (tal como lo es ahora), excepto que el diccionario de variables locales se reemplaza por el diccionario devuelto desde __prepare__ . Este objeto de diccionario puede ser un diccionario regular o un tipo de mapeo personalizado.

 ... 

Un ejemplo sería una metaclase que usa información sobre el orden de las declaraciones de los miembros para crear una estructura. La metaclase proporcionaría un diccionario personalizado que simplemente mantiene un registro del orden de las inserciones.

No desea “crear una estructura en C” como en este ejemplo, pero el orden de los campos es crucial (para permitir el uso de los parámetros posicionales que desee), por lo que la metaclase personalizada (obtenida a través del model base) tendría una __prepare__ classmethod devolver un diccionario ordenado. Esto elimina el problema específico, pero, por supuesto, solo si estás dispuesto a cambiar todo tu código usando este “ORM mágico” a Python 3. ¿Lo harías?

Una vez resuelto, el problema es qué operaciones de base de datos desea realizar y cómo. Su ejemplo, por supuesto, no aclara esto en absoluto. ¿Es especial el nombre del atributo taskList , o debería algún otro atributo asignado al objeto db “guardado automáticamente” (por nombre y, qué otras características [s]?) Y “recuperarse automáticamente” al usarlo? ¿Hay formas de eliminar entidades, alterarlas, ubicarlas (de lo contrario, una vez que se hayan incluido en el mismo atributo del objeto db )? ¿Cómo sabe su código de muestra qué servicio de base de datos debe usar y cómo autenticarlo (p. Ej., Mediante ID de usuario y contraseña) si requiere autenticación?

Las tareas específicas que enumera no serían difíciles de implementar (por ejemplo, encima del servicio de almacenamiento de Google App Engine, que no requiere autenticación ni especificación de “qué servicio de DB debe usar”). la metaclase del model introspeccionaría los campos de la clase y generaría un Model GAE para la clase, el objeto db usaría __setattr__ para establecer un desencadenante atexit para almacenar el valor final de un atributo (como una entidad en un tipo diferente de Model por supuesto) y __getattr__ para recuperar la información de ese atributo del almacenamiento. Por supuesto, sin alguna funcionalidad de base de datos adicional, todo esto sería bastante inútil ;-).

Edición : así que hice un pequeño prototipo (Python 2.6 y basado en sqlite) y lo puse en http://www.aleax.it/lustdb.zip . Es un archivo zip de 3K que incluye 225 líneas de lustdb.py (también mucho tiempo para publicar aquí) y dos pequeños archivos de prueba aproximadamente equivalentes a los originales del OP: test0.py es …:

 from lustdb import * class Task(Model): title = '' done = False db.taskList = [] db.taskList.append(Task(title='Beat old sql interfaces', done=False)) db.taskList.append(Task(title='Illustrate different syntax modes', done=True)) 

y test1.p1 es …:

 from lustdb import * print 'Done tasks:' for task in db.taskList: if task.done: print task 

Ejecutar test0.py (en una máquina con un directorio grabable /tmp , es decir, cualquier sistema operativo Unix-y, o, en Windows, uno en el que se haya ejecutado un mkdir \tmp en cualquier momento anterior 😉 no tiene salida; Después de eso, ejecutando test1.py salidas de test1.py :

 Done tasks: Task(done=True, title=u'Illustrate different syntax modes') 

Tenga en cuenta que estos son mucho menos “locamente mágicos” que los ejemplos del OP, de muchas maneras, como …

 1. no (expletive delete) redundancy whereby `db.taskList` is a synonym of `db['taskList']`, only the sensible former syntax (attribute-access) is supported 2. no mysterious (and totally crazy) way whereby a `done` attribute magically becomes `isDone` instead midway through the code 3. no mysterious (and utterly batty) way whereby a `print task` arbitrarily (or magically?) picks and prints just one of the attributes of the task 4. no weird gyrations and incantations to allow positional-attributes in lieu of named ones (this one the OP agreed to) 

Por supuesto, el prototipo (como los prototipos 😉 deja mucho que desear en muchos aspectos (claridad, documentación, pruebas unitarias, optimización, verificación de errores y diagnóstico, portabilidad entre diferentes back-ends y especialmente características de DB más allá de las implícitas en la pregunta). Las características de la base de datos que faltan son legión (por ejemplo, los ejemplos originales del OP no dan forma de identificar una “clave principal” para un modelo, ni ningún otro tipo de restricciones de unicidad, por lo que los duplicados pueden abundar; y solo empeora a partir de ahí; ). Sin embargo, para 225 líneas (190 netos de líneas vacías, comentarios y cadenas de documentación ;-), no es tan malo en mi opinión parcial.

La forma correcta de continuar jugando con este proyecto sería, por supuesto, iniciar un nuevo proyecto de código abierto lustdb en la parte de alojamiento de code.google.com (o cualquier otro sitio de alojamiento de código abierto con seguimiento de problemas, wiki, soporte de revisiones de código, Navegación en línea, soporte DVCS, etc., etc.) Lo haría yo mismo, pero estoy cerca del límite en cuanto a la cantidad de proyectos de código abierto que puedo iniciar en code.google.com y no quiero “grabar”. “el último o los dos de esta manera ;-).

Por cierto, el nombre lustdb para el módulo es un juego de palabras con las iniciales del OP (las dos primeras letras cada una de los nombres y apellidos), en la tradición de awk y amigos: creo que suena bien (y la mayoría de los otros nombres obvios como como se simpledb y dumbdb ;-).

Creo que deberías probar ZODB . Es una base de datos orientada a objetos diseñada para almacenar objetos de Python. Su API es muy similar al ejemplo que ha proporcionado en su pregunta, solo eche un vistazo al tutorial.

¿Qué pasa con el uso de Elixir ?

¡Olvídate de ORM! Me gusta el vainilla SQL. Los envoltorios de python como psycopg2 para postgreSQL hacen conversión automática de tipos, ofrecen una protección bastante buena contra la inyección de SQL y son agradables y simples.

 sql = "SELECT * FROM table WHERE id=%s" data = (5,) cursor.execute(sql, data) 

Cuanto más pienso, más parece que el modelo de operación de Smalltalk parece más relevante. De hecho, es posible que el OP no haya llegado lo suficientemente lejos al usar el término “base de datos” para describir una cosa que no debería tener necesidad de nombrar.

Un intérprete de Python en ejecución tiene una stack de objetos que viven en la memoria. Sus interrelaciones pueden ser arbitrariamente complejas, pero los espacios de nombres y las “tags” a las que están vinculados los objetos son muy flexibles. Y como pickle puede serializar de manera explícita estructuras arbitrarias para la persistencia, no parece que haya mucho scope al considerar a cada intérprete de Python que vive en ese espacio de objetos. ¿Por qué ese espacio de objetos se evapora con el cierre del intérprete? Semánticamente, esto podría verse como una extensión de los diccionarios empatados anydbm . Y como casi todo en Python es como un diccionario, el mecanismo ya casi está allí.

Creo que este puede ser el modelo genérico que Alex Martelli propuso anteriormente, podría ser bueno decir algo como:

 class Book: def __init__(self, attributes): self.attributes = attributes def __getattr__(....): pass $ python >>> import book >>> my_stuff.library = {'garp': Book({'author': 'John Irving', 'title': 'The World According to Garp', 'isbn': '0-525-23770-4', 'location': 'kitchen table', 'bookmark': 'page 127'}), ... } >>> exit 

[en algún momento de la próxima semana]

 $ python >>> import my_stuff >>> print my_stuff.library['garp'].location 'kitchen table' # or even >>> for book in my_stuff.library where book.location.contains('kitchen'): print book.title 

No sé si llamaría al lenguaje resultante Python, pero parece que no es tan difícil de implementar y hace que la tienda de respaldo sea equivalente a la tienda activa.

Existe una tensión natural entre la estructura inherente impuesta, y algunas veces deseada, por los RDBM y la forma de mirar el ombligo de forma libre aquí, pero las bases de datos NoSQLy ya se están acercando al modelo de memoria de contenido direccionable y probablemente se aproxima mejor a cómo nuestras mentes siguen la pista. cosas. Por el contrario, no querría mantener todas las órdenes de compra corporativas como un sistema de almacenamiento, pero tal vez podría hacerlo.

¿Qué tal si da un ejemplo de lo “simple” que quiere que sea su “relación con la base de datos” y luego le digo todo lo que se necesita para que esa “simplicidad” funcione?

(Y de lo cual aún será USTED quien deberá proporcionar la información / configuración al motor de interfaz de la base de datos, en algún lugar, de alguna manera).

Para nombrar solo un ejemplo:

Si el motor de administración de su base de datos es una máquina externa con la que usted / su aplicación se interconecta a través de IP o algo similar, no hay forma de evitar que la identidad de IP donde se ejecuta el motor de la base de datos deba ser proporcionada por la base de datos de su aplicación. interfaz cliente, en alguna parte, de alguna manera. Independientemente de si eso se expone explícitamente en el código o no.

He estado ocupado, aquí está, publicado bajo LGPL: http://github.com/lukestanley/lustdb

Utiliza JSON como backend en este momento.

Este no es el mismo código que Alex Martelli hizo. Quería hacer el código más legible y reutilizable con diferentes backends y similares.

En otros lugares, he estado trabajando en elementos HTML orientados a objetos accesibles en Python de manera similar, Y en una biblioteca para hacer que web.py sea más minimalista.

Estoy pensando en formas de usar los 3 elementos junto con la construcción automática de prototipos MVC o mapeo inteligente.

Si bien la progtwigción web basada en plantillas de texto a la antigua seguirá existiendo por un tiempo debido a los sistemas heredados y debido a que no requiere ninguna biblioteca o implementación en particular, creo que pronto tendremos formas mucho más eficientes de crear dispositivos robustos y compatibles con los prototipos. aplicaciones web

Por favor, consulte la lista de correo para los interesados.

Si te gusta CherryPy, quizás te gusten los ORM complementarios que escribí: GeniuSQL (que sigue un modelo de pasarela de datos de tabla) y Dejavu (que es un completo Mapeador de datos).

Hay demasiadas preguntas en esta pregunta y todos sus subcomentarios para abordar por completo, pero una cosa que quería señalar es que GeniuSQL y Dejavu tienen un sistema muy robusto para asignar tipos nativos de Python a los tipos que usa su backend particular. Hay valores predeterminados muy sanos, que se pueden anular según sea necesario, e incluso extenderse si se crea un nuevo backend o se utilizan tipos de un backend que aún no son compatibles. Consulte http://www.aminus.net/geniusql/chrome/common/doc/trunk/advanced.html#custom para obtener más información al respecto.