SQLAlchemy可以添加新记录并自动化表之间的关系而无需手动检查PK唯一性吗?

joh*_*s85 5 python sqlalchemy primary-key relational-database

我是SQLAlchemy的新手,并阅读了基本文档.我目前正在关注Mike Driscoll的MediaLocker教程并根据自己的目的修改/扩展它.

我有三张桌子(贷款,人,卡).贷款卡和贷款人都是一对多的关系,并建模如下:

from sqlalchemy import Table, Column, DateTime, Integer, ForeignKey, Unicode
from sqlalchemy.orm import backref, relation
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine("sqlite:///cardsys.db", echo=True)
DeclarativeBase = declarative_base(engine)
metadata = DeclarativeBase.metadata

class Loan(DeclarativeBase):
    """
    Loan model
    """

    __tablename__ = "loans"

    id = Column(Integer, primary_key=True)
    card_id = Column(Unicode, ForeignKey("cards.id"))
    person_id = Column(Unicode, ForeignKey("people.id"))
    date_issued = Column(DateTime)
    date_due = Column(DateTime)
    date_returned = Column(DateTime)
    issue_reason = Column(Unicode(50))
    person = relation("Person", backref="loans", cascade_backrefs=False)
    card = relation("Card", backref="loans", cascade_backrefs=False)

class Card(DeclarativeBase):
    """
    Card model
    """

    __tablename__ = "cards"

    id = Column(Unicode(50), primary_key=True)
    active = Column(Boolean)

class Person(DeclarativeBase):
    """
    Person model
    """

    __tablename__ = "people"

    id = Column(Unicode(50), primary_key=True)
    fname = Column(Unicode(50))
    sname = Column(Unicode(50))
Run Code Online (Sandbox Code Playgroud)

当我尝试创建一个新的贷款(在我的控制器中使用以下方法)它适用于独特的卡和人,但一旦我尝试为特定的人或卡添加第二笔贷款,它给我一个"非独特"错误.显然它并不是唯一的,这就是重点,但我认为SQLAlchemy会为我处理幕后的事情,并在新贷款中添加正确的现有人或卡ID作为FK,而不是试图创建新的人和卡片记录.是否由我来查询数据库以检查PK唯一性并手动处理?我觉得这应该是SQLAlchemy可以自动处理的东西吗?

def addLoan(session, data):

    loan = Loan()
    loan.date_due = data["loan"]["date_due"]
    loan.date_issued = data["loan"]["date_issued"]
    loan.issue_reason = data["loan"]["issue_reason"]

    person = Person()
    person.id = data["person"]["id"]
    person.fname = data["person"]["fname"]
    person.sname = data["person"]["sname"]
    loan.person = person

    card = Card()
    card.id = data["card"]["id"]
    loan.card = card

    session.add(loan)
    session.commit()
Run Code Online (Sandbox Code Playgroud)

在MediaLocker示例中,使用自动增量PK创建新行(即使对于重复项,也不符合规范化规则).我希望有一个规范化的数据库(即使是在一个小项目中,只是为了学习的最佳实践),但是在网上找不到任何学习的例子.

我怎样才能实现上述目标?

rob*_*jpg 5

在尝试添加具有重复主键的新对象之前,您可以检索并将现有对象PersonCard对象分配给关系.您可以通过对代码进行一些小的更改来完成此操作.

def addLoan(session, data):

    loan = Loan()
    loan.date_due = data["loan"]["date_due"]
    loan.date_issued = data["loan"]["date_issued"]
    loan.issue_reason = data["loan"]["issue_reason"]

    person = session.query(Person).get(data["person"]["id"])
    if not person:
        person = Person()
        person.id = data["person"]["id"]
        person.fname = data["person"]["fname"]
        person.sname = data["person"]["sname"]
    loan.person = person

    card = session(Card).query.get(data["card"]["id"])
    if not card:
        card = Card()
        card.id = data["card"]["id"]
    loan.card = card

    session.add(loan)
    session.commit()
Run Code Online (Sandbox Code Playgroud)

如果要将其包装到一个步骤中,还有一些get_or_create函数的解决方案.

如果您从头开始将大量记录加载到新数据库中,并且您的查询比a get(会话对象应该get自行缓存查找)更复杂,那么您可以完全避免查询以内存为代价.通过ID将每个新的Person和Card对象添加到临时dict,并在那里检索现有对象而不是命中数据库.