Edw*_*rdr 2 python database database-design sqlalchemy
我正在努力让以下模型协同工作.首先,情景如下:
电子邮件地址是用户的ID,因此他们必须始终拥有一个,但是当他们更改它时,我想跟踪他们过去使用过的其他内容.到目前为止,设置是有一个帮助表user_emails,在电子邮件和用户之间保持联系,我听说不应该将其设置为使用声明性SQLAlchemy方法的类(虽然我不知道为什么).另外,我认为我需要使用是正确的,use_alter=True因为在插入之前users表不会知道外键email_id吗?
models.py 看起来像这样:
"""models.py"""
user_emails = Table('user_emails', Base.metadata,
Column('user_id', Integer, ForeignKey('users.id'),
primary_key=True),
Column('email', String(50), ForeignKey('emails.address'),
primary_key=True))
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('usr_id_seq', start=100, increment=1),
primary_key=True)
email_id = Column(String(50),
ForeignKey('emails.address', use_alter=True, name='fk_email_id'),
unique=True, nullable=False)
first = Column(String(25), unique=True, nullable=False)
last = Column(String(25), unique=True, nullable=False)
def __init__(self, first, last):
self.first = first
self.last = last
class Email(Base):
__tablename__ = 'emails'
address = Column(String(50), unique=True, primary_key=True)
user = relationship(User, secondary=user_emails, backref='emails')
added = Column(DateTime, nullable=False)
verified = Column(Boolean, nullable=False)
def __init__(self, address, added, verified=False):
self.address = address
self.added = added
self.verified = verified
Run Code Online (Sandbox Code Playgroud)
在我尝试提交数据库之前,一切似乎都没问题:
>>> user = models.User("first", "last")
>>> addy = models.Email("example@example.com", datetime.datetime.utcnow())
>>> addy
<Email 'example@example.com' (verified: False)>
>>> user
>>> <User None (active: True)>
>>>
>>> user.email_id = addy
>>> user
>>> <User <Email 'example@example.com' (verified: False)> (active: True)>
>>> Session.add_all([user, addy])
>>> Session.commit()
>>> ...
>>> sqlalchemy.exc.ProgrammingError: (ProgrammingError) can't adapt type 'Email' "INSERT INTO users (id, email_id, first, last, active) VALUES (nextval('usr_id_seq'), %(email_id)s, %(first)s, %(last)s, %(active)s) RETURNING users.id" {'last': 'last', 'email_id': <Email 'example@example.com' (verified: False)>, 'active': True, 'first': 'first'}
Run Code Online (Sandbox Code Playgroud)
所以,我认为我做错了什么/傻,但我是SQLAlchemy的新手,所以我不确定我需要做些什么来正确设置模型.
最后,假设我得到了正确的模型设置,是否可以添加关系,以便通过加载任意电子邮件对象,我将能够从Email对象中的属性访问拥有它的用户?
谢谢!
您已经有了一个非常好的解决方案,一个小修补程序将使您的代码工作.请在下面找到有关您的代码的快速反馈:
use_alter=True吗?不,你实际上不需要那个.如果primary_key该Email表是计算在数据库级别上(与autoincrement基于主键),那么你可能当你有两个表需要foreign_keys对方.在你的情况下,你甚至没有,因为你有第三个表,所以对于任何关系组合,SA (sqlalchemy)将通过插入新的电子邮件,然后插入用户,然后关系来解决它.Email来User.email_id这是为了获得email唯一的价值.有两种方法可以解决它:
user.email_id = addy改为user.email_id = addy.addressrelationship然后进行分配(参见下面的代码).就个人而言,我更喜欢选项-2.User.email_id实际上是其中之一User.emails.这可能是由设计,但其他人只需添加一个ForeignKey从[users.id, users.email_id] to [user_emails.user_id, user_emails.email]版本2的示例代码:
""" models.py """
class User(Base):
__tablename__ = 'users'
# ...
email_id = Column(String(50),
ForeignKey('emails.address', use_alter=True,
name='fk_email_id'), unique=True,
nullable=False)
default_email = relationship("Email", backref="default_for_user")
""" script """
# ... (all that you have below until next line)
# user.email_id = addy.address
user.default_email = addy
Run Code Online (Sandbox Code Playgroud)