tutorial not in_ example español create python sqlalchemy

python - not - ¿Debo crear objetos mapper o usar la sintaxis declarativa en SQLAlchemy?



sqlalchemy select example (3)

"Lo que no estoy del todo seguro, ¿cuál es el enfoque más fácil de mantener para una aplicación de negocios?"

No se puede responder en general.

Sin embargo, considera esto.

El ORM de Django es estrictamente declarativo, y a la gente le gusta eso.

SQLAlchemy hace varias cosas, no todas son relevantes para todos los problemas.

  1. SQLAlchemy crea un SQL específico de DB desde Python de propósito general. Si quiere meterse con el SQL, o asignar clases de Python a tablas existentes, entonces tiene que usar mapeos explícitos, porque su atención se centra en el SQL, no en los objetos comerciales y el ORM.

  2. SQLAlchemy puede usar un estilo declarativo (como Django) para crear todo para usted. Si quieres esto, entonces estás renunciando a escribir explícitamente definiciones de tabla y jugando explícitamente con el SQL.

  3. Elixir es una alternativa para evitar tener que mirar SQL.

La pregunta fundamental es "¿Quieres ver y tocar el SQL?"

Si crees que tocar el SQL hace que las cosas sean más "mantenibles", entonces debes usar mapeos explícitos.

Si crees que ocultar el SQL hace que las cosas sean más "mantenibles", entonces tienes que usar el estilo declarativo.

  • Si crees que Elixir puede diferir de SQLAlchemy, o no cumplir su promesa de alguna manera, entonces no la uses.

  • Si crees que Elixir te ayudará, entonces úsalo.

Hay dos (tres, pero no estoy contando Elixir , ya que no es "oficial") formas de definir un objeto persistente con SQLAlchemy :

Sintaxis explícita para objetos mapeadores

from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey from sqlalchemy.orm import mapper metadata = MetaData() users_table = Table(''users'', metadata, Column(''id'', Integer, primary_key=True), Column(''name'', String), ) class User(object): def __init__(self, name): self.name = name def __repr__(self): return "<User(''%s'')>" % (self.name) mapper(User, users_table) # &lt;Mapper at 0x...; User&gt;

Sintaxis declarativa

from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = ''users'' id = Column(Integer, primary_key=True) name = Column(String) def __init__(self, name): self.name = name def __repr__(self): return "<User(''%s'')>" % (self.name)

Puedo ver que al usar los objetos del mapeador, separo completamente la definición del ORM de la lógica comercial, mientras uso la sintaxis declarativa, cada vez que modifico la clase lógica de negocios, puedo editar allí la clase de la base de datos (que idealmente debería ser editada )

Lo que no estoy del todo seguro, ¿cuál es el enfoque más fácil de mantener para una aplicación comercial?

No he podido encontrar una comparación entre los dos métodos de mapeo, para poder decidir cuál se ajusta mejor a mi proyecto.

Me inclino por usar la forma "normal" (es decir, no la extensión declarativa) ya que me permite "ocultarme", y mantener fuera de la vista empresarial toda la lógica de ORM, pero me gustaría escuchar argumentos convincentes para ambos enfoques.


Descubrí que usar objetos mapper es mucho más simple que la sintaxis declarativa si usa sqlalchemy-migrate para versionar el esquema de la base de datos (y esta es una herramienta imprescindible para una aplicación comercial desde mi punto de vista). Si está utilizando objetos mapper, puede simplemente copiar / pegar las declaraciones de la tabla en las versiones de migración y usar api simple para modificar tablas en la base de datos. La sintaxis declarativa hace esto más difícil porque debe filtrar todas las funciones auxiliares de las definiciones de clase después de copiarlas en la versión de migración.

Además, me parece que las relaciones complejas entre tablas se expresan más claramente con la sintaxis de objetos mapeadores, pero esto puede ser subjetivo.


En nuestro equipo establecimos la sintaxis declarativa.

Razón fundamental:

  • metadata son triviales, si es necesario: User.metadata .
  • Su clase de User , en virtud de la subclasificación de Base , tiene un buen código que toma kwargs para todos los campos. Útil para probar y de lo contrario. Ejemplo: user=User(name=''doe'', password=''42'') . ¡Entonces no es necesario escribir un ctor!
  • Si agrega un atributo / columna, solo necesita hacerlo una vez. "No repetir" es un buen principio.

En cuanto a "mantener el ORM fuera de la vista comercial": en realidad, su clase de User , definida de una manera "normal", recibe un parche serio por parte de SA cuando la función de mapper sale con la suya. En mi humilde opinión, el modo declarativo es más sincero porque grita: "esta clase se usa en escenarios ORM, y no se puede tratar como trataría sus objetos simples que no son ORM".