SQLAlchemy插入多对一条目
抱歉,如果这是一个新手问题,但是关于的文档似乎没有涵盖这一点。我一直在寻找类似于How to Insert/Add Data to Your Tables(如何向表插入/添加数据)部分的内容,但是在所示的示例中,这始终是一个独特的插入 基本上,我想用本地机器上的数据填充数据库。为了简单起见,我已经将下面所示的示例构建成一个MWE来说明这个问题。这个问题由两个名为Price和Currency的表组成,实现是以声明式方式完成的 model.py 从sqlalchemy导入列,整数,字符串 从sqlalchemy导入Float、BigInteger、ForeignKey 从sqlalchemy.orm导入关系,backref 从sqlalchemy.ext.declarative导入声明性基础 Base=声明性的\u Base 类别库: __tablename_uu='货币' id=ColumnInteger,主键=True 单位=ColumnString16,唯一=True 定义初始自我,单位: self.unit=单位 类别价格基数: __tablename_uuu=‘价格’ id=ColumnBigInteger,主键=True currency_id=ColumnInteger,ForeignKeyCurrency.id,nullable=False currency=relationshipCurrency,backref=currency.id hour1=列浮点 hour2=列浮点 定义初始自我,小时1,小时2: self.hour1=hour1 self.hour2=hour2 目前,我正在使用以下代码填充数据库: script.py 从sqlalchemy导入创建引擎 从sqlalchemy.orm导入作用域的_会话,sessionmaker 从模型导入* 引擎=创建引擎'sqlite:///example.db,echo=True db_session=scoped_sessionsMakerautommit=False, 自动刷新=错误, 绑定=引擎 会话=db_会话 Base.metadata.create_allengine oPrice=价格2.5,2.5 oPrice.currency=货币欧元 session.addoPrice t价格=价格5.5,1.5 tPrice.currency=CurrencyEUR session.addtPrice session.commit 这会产生一个错误 sqlalchemy.exc.IntegrityError:IntegrityError列单位不唯一u'插入货币单位值“EUR”SQLAlchemy插入多对一条目,sqlalchemy,many-to-one,Sqlalchemy,Many To One,抱歉,如果这是一个新手问题,但是关于的文档似乎没有涵盖这一点。我一直在寻找类似于How to Insert/Add Data to Your Tables(如何向表插入/添加数据)部分的内容,但是在所示的示例中,这始终是一个独特的插入 基本上,我想用本地机器上的数据填充数据库。为了简单起见,我已经将下面所示的示例构建成一个MWE来说明这个问题。这个问题由两个名为Price和Currency的表组成,实现是以声明式方式完成的 model.py 从sqlalchemy导入列,整数,字符串 从sql
填充数据库的最佳策略是什么,以确保Currency.id和Price.Currency\u id映射正确?我应该让模型类在初始化之前寻找唯一性吗?我应该在与另一个表关联时这样做吗?最简单的解决方案是使用货币代码作为货币中的主键,使用外键作为价格中的外键。那你就可以
price.currency_id = "EUR"
这也使您的数据库表更具可读性—例如,您将不会有28342,而是“GBP”。最简单的解决方案是使用货币代码作为货币的主键,而使用外键作为价格。那你就可以
price.currency_id = "EUR"
这也使您的数据库表更具可读性-例如,您将不会有28342,而是“GBP”。我支持Antti的建议,因为货币有标准代码,如“INR”、“USD”等,您可以将货币代码作为主键 或者,如果要保留数字主键,则其中一个选项是: 根据上面链接中的配方编辑添加示例,该配方具有DeCartor类 database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine('sqlite:///example.db', echo=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
model.py
from sqlalchemy import Column, Integer, String
from sqlalchemy import Float, BigInteger, ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base
from database import db_session
Base = declarative_base()
def _unique(session, cls, hashfunc, queryfunc, constructor, arg, kw):
cache = getattr(session, '_unique_cache', None)
if cache is None:
session._unique_cache = cache = {}
key = (cls, hashfunc(*arg, **kw))
if key in cache:
return cache[key]
else:
with session.no_autoflush:
q = session.query(cls)
q = queryfunc(q, *arg, **kw)
obj = q.first()
if not obj:
obj = constructor(*arg, **kw)
session.add(obj)
cache[key] = obj
return obj
def unique_constructor(scoped_session, hashfunc, queryfunc):
def decorate(cls):
def _null_init(self, *arg, **kw):
pass
def __new__(cls, bases, *arg, **kw):
# no-op __new__(), called
# by the loading procedure
if not arg and not kw:
return object.__new__(cls)
session = scoped_session()
def constructor(*arg, **kw):
obj = object.__new__(cls)
obj._init(*arg, **kw)
return obj
return _unique(
session,
cls,
hashfunc,
queryfunc,
constructor,
arg, kw
)
# note: cls must be already mapped for this part to work
cls._init = cls.__init__
cls.__init__ = _null_init
cls.__new__ = classmethod(__new__)
return cls
return decorate
@unique_constructor(
db_session,
lambda unit: unit,
lambda query, unit: query.filter(Currency.unit == unit)
)
class Currency(Base):
__tablename__ = 'Currency'
id = Column(Integer, primary_key=True)
unit = Column(String(16), unique=True)
def __init__(self, unit):
self.unit = unit
class Price(Base):
__tablename__ = 'Price'
id = Column(BigInteger, primary_key=True)
currency_id = Column(Integer, ForeignKey("Currency.id"), nullable=False)
currency = relationship("Currency", backref="Currency.id")
hour1 = Column(Float)
hour2 = Column(Float)
def __init__(self, hour1, hour2):
self.hour1 = hour1
self.hour2 = hour2
script.py:
from model import *
from database import engine, db_session as session
Base.metadata.create_all(engine)
oPrice = Price(2.5, 2.5)
oPrice.currency = Currency("EUR")
session.add(oPrice)
tPrice = Price(5.5, 1.5)
tPrice.currency = Currency("EUR")
session.add(tPrice)
session.commit()
我支持Antti的建议,因为货币有标准代码,如“INR”、“USD”等,所以可以将货币代码作为主键 或者,如果要保留数字主键,则其中一个选项是: 根据上面链接中的配方编辑添加示例,该配方具有DeCartor类 database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine('sqlite:///example.db', echo=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
model.py
from sqlalchemy import Column, Integer, String
from sqlalchemy import Float, BigInteger, ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base
from database import db_session
Base = declarative_base()
def _unique(session, cls, hashfunc, queryfunc, constructor, arg, kw):
cache = getattr(session, '_unique_cache', None)
if cache is None:
session._unique_cache = cache = {}
key = (cls, hashfunc(*arg, **kw))
if key in cache:
return cache[key]
else:
with session.no_autoflush:
q = session.query(cls)
q = queryfunc(q, *arg, **kw)
obj = q.first()
if not obj:
obj = constructor(*arg, **kw)
session.add(obj)
cache[key] = obj
return obj
def unique_constructor(scoped_session, hashfunc, queryfunc):
def decorate(cls):
def _null_init(self, *arg, **kw):
pass
def __new__(cls, bases, *arg, **kw):
# no-op __new__(), called
# by the loading procedure
if not arg and not kw:
return object.__new__(cls)
session = scoped_session()
def constructor(*arg, **kw):
obj = object.__new__(cls)
obj._init(*arg, **kw)
return obj
return _unique(
session,
cls,
hashfunc,
queryfunc,
constructor,
arg, kw
)
# note: cls must be already mapped for this part to work
cls._init = cls.__init__
cls.__init__ = _null_init
cls.__new__ = classmethod(__new__)
return cls
return decorate
@unique_constructor(
db_session,
lambda unit: unit,
lambda query, unit: query.filter(Currency.unit == unit)
)
class Currency(Base):
__tablename__ = 'Currency'
id = Column(Integer, primary_key=True)
unit = Column(String(16), unique=True)
def __init__(self, unit):
self.unit = unit
class Price(Base):
__tablename__ = 'Price'
id = Column(BigInteger, primary_key=True)
currency_id = Column(Integer, ForeignKey("Currency.id"), nullable=False)
currency = relationship("Currency", backref="Currency.id")
hour1 = Column(Float)
hour2 = Column(Float)
def __init__(self, hour1, hour2):
self.hour1 = hour1
self.hour2 = hour2
script.py:
from model import *
from database import engine, db_session as session
Base.metadata.create_all(engine)
oPrice = Price(2.5, 2.5)
oPrice.currency = Currency("EUR")
session.add(oPrice)
tPrice = Price(5.5, 1.5)
tPrice.currency = Currency("EUR")
session.add(tPrice)
session.commit()
我有一个模糊的记忆,我看到了一个更好的模式,没有在Trac页面上,但找不到它…如果你能举个例子,我会非常感激。我有一个模糊的记忆,我看到了一个更好的模式,没有在Trac页面上,但找不到它…如果你能举个例子,我真的很感激。对于这个简化的问题,我同意,但我有多个表,价格表中的条目有多列,不太容易取整。对于这个简化的问题,我同意,但我有多个表,价格表中的条目有多列,不太容易取整。