在 sqlalchemy 中定义 ORM 关系
Defining ORM relationships in sqlalchemy
我正一头扎进 sqlalchemy ORM 并试图理解对象之间的关系。
我创建了 3 个 classes 分别代表日志文件 (Log)、从日志文件解析的记录 (LogRecord) 和每个日志记录所属的用户 (User)。
我是这样定义 classes 的:
from sqlalchemy import Table, Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import random
engine = create_engine('sqlite://')
# Create the session class
Session = sessionmaker(bind=engine)
# Create the session
session = Session()
Base = declarative_base()
class Log(Base):
__tablename__ = 'logs'
id = Column(Integer, primary_key=True, unique=True)
log_name = Column(String, unique=True)
records = relationship("LogRecord", backref="logs")
def __repr__(self):
return '<Log(log_name={:s}, id={:d}>'.format(
self.log_name, self.id)
class LogRecord(Base):
__tablename__ = 'log_records'
id = Column(Integer, primary_key=True, unique=True)
record_name = Column(String)
log_id = Column(Integer, ForeignKey('logs.id'))
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship("User", backref="log_records")
def __repr__(self):
return '<LogRecord(record_name={:s}, id={:d}>'.format(
self.record_name,
self.id)
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, unique=True)
name = Column(String, unique=True)
def __repr__(self):
return '<User(name={:s}, id={:d}>'.format(self.name, self.id)
然后用一些虚假数据填充它们:
Base.metadata.create_all(engine)
users = ['John', 'Alex', 'Nikki']
# Add 10 log files to Log
for x in range(0,10):
log = Log(log_name='log{:d}.txt'.format(x))
session.add(log)
# Add users
for user in users:
session.add(User(name=user))
# Select all users
users = session.query(User).all()
# Add log records
for log in session.query(Log):
# Assign a random user to each log record
user = users[int(random.random() * len(users))]
for x in range(0,10):
# Assign a random user to each log record
user = users[int(random.random() * len(users))]
r = LogRecord(record_name='{:s}-{:d}'.format(log.log_name, int(random.random()*100)),log_id=log.id,user=user)
session.add(r)
每个日志文件可以包含一个或多个用户的记录。我想获得一个不同的日志文件列表,其中至少包含来自指定用户的一条记录。我试过了:
In [8]: user = session.query(User).filter(User.name == 'John').one()
In [9]: user
Out[9]: <User(name=John, id=1>
然后尝试使用以下方法查找日志:
In [10]: session.query(Log).filter(Log.records.user == user).all()
但得到了以下信息:
session.query(Log).filter(Log.records.user == user).distinct().all()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-13-d6d323e178f8> in <module>()
----> 1 session.query(Log).filter(Log.records.user == user).distinct().all()
/Users/kerfoot/code/venvs/sqlalchemy/lib/python2.7/sitepackages/sqlalchemy/orm/attributes.pyc in __getattr__(self, key)
192 type(self.comparator).__name__,
193 self,
--> 194 key)
195 )
196
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Log.records has an attribute 'user'
不确定我的 class defs 或查询本身是否有问题。
非常感谢任何帮助!
您不能对属性属性进行过滤,或者简单地说:表达式中不能有多个点:Log.records.user
不工作。
Option-1: 你可以像在 SQL:
中那样做
session.query(Log).join(LogRecord, Log.records).filter(LogRecord.user == user).all()
和 sqlalchemy
足够聪明 return 你只有 Log
个实例的列表而没有任何重复(即使 SQL 语句可能会导致重复)。
Option-2: 另一种方法是使用 any(...)
,这在逻辑上 更干净:
session.query(Log).filter(Log.records.any(LogRecord.user == user)).all()
Transcript:
-> get all Log
instances,
-> which contains at least one LogRecord
,
-> that belongs to given user
.
我正一头扎进 sqlalchemy ORM 并试图理解对象之间的关系。
我创建了 3 个 classes 分别代表日志文件 (Log)、从日志文件解析的记录 (LogRecord) 和每个日志记录所属的用户 (User)。
我是这样定义 classes 的:
from sqlalchemy import Table, Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import random
engine = create_engine('sqlite://')
# Create the session class
Session = sessionmaker(bind=engine)
# Create the session
session = Session()
Base = declarative_base()
class Log(Base):
__tablename__ = 'logs'
id = Column(Integer, primary_key=True, unique=True)
log_name = Column(String, unique=True)
records = relationship("LogRecord", backref="logs")
def __repr__(self):
return '<Log(log_name={:s}, id={:d}>'.format(
self.log_name, self.id)
class LogRecord(Base):
__tablename__ = 'log_records'
id = Column(Integer, primary_key=True, unique=True)
record_name = Column(String)
log_id = Column(Integer, ForeignKey('logs.id'))
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship("User", backref="log_records")
def __repr__(self):
return '<LogRecord(record_name={:s}, id={:d}>'.format(
self.record_name,
self.id)
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, unique=True)
name = Column(String, unique=True)
def __repr__(self):
return '<User(name={:s}, id={:d}>'.format(self.name, self.id)
然后用一些虚假数据填充它们:
Base.metadata.create_all(engine)
users = ['John', 'Alex', 'Nikki']
# Add 10 log files to Log
for x in range(0,10):
log = Log(log_name='log{:d}.txt'.format(x))
session.add(log)
# Add users
for user in users:
session.add(User(name=user))
# Select all users
users = session.query(User).all()
# Add log records
for log in session.query(Log):
# Assign a random user to each log record
user = users[int(random.random() * len(users))]
for x in range(0,10):
# Assign a random user to each log record
user = users[int(random.random() * len(users))]
r = LogRecord(record_name='{:s}-{:d}'.format(log.log_name, int(random.random()*100)),log_id=log.id,user=user)
session.add(r)
每个日志文件可以包含一个或多个用户的记录。我想获得一个不同的日志文件列表,其中至少包含来自指定用户的一条记录。我试过了:
In [8]: user = session.query(User).filter(User.name == 'John').one()
In [9]: user
Out[9]: <User(name=John, id=1>
然后尝试使用以下方法查找日志:
In [10]: session.query(Log).filter(Log.records.user == user).all()
但得到了以下信息:
session.query(Log).filter(Log.records.user == user).distinct().all()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-13-d6d323e178f8> in <module>()
----> 1 session.query(Log).filter(Log.records.user == user).distinct().all()
/Users/kerfoot/code/venvs/sqlalchemy/lib/python2.7/sitepackages/sqlalchemy/orm/attributes.pyc in __getattr__(self, key)
192 type(self.comparator).__name__,
193 self,
--> 194 key)
195 )
196
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Log.records has an attribute 'user'
不确定我的 class defs 或查询本身是否有问题。
非常感谢任何帮助!
您不能对属性属性进行过滤,或者简单地说:表达式中不能有多个点:Log.records.user
不工作。
Option-1: 你可以像在 SQL:
中那样做session.query(Log).join(LogRecord, Log.records).filter(LogRecord.user == user).all()
和 sqlalchemy
足够聪明 return 你只有 Log
个实例的列表而没有任何重复(即使 SQL 语句可能会导致重复)。
Option-2: 另一种方法是使用 any(...)
,这在逻辑上 更干净:
session.query(Log).filter(Log.records.any(LogRecord.user == user)).all()
Transcript:
-> get allLog
instances,
-> which contains at least oneLogRecord
,
-> that belongs to givenuser
.