Может ли SQLAlchemy добавлять новые записи и автоматизировать отношения между таблицами, не проверяя вручную уникальность PK? - PullRequest
5 голосов
/ 08 февраля 2012

Я относительный новичок в SQLAlchemy и ознакомился с основными документами.В настоящее время я следую учебному пособию Майка Дрисколла Майка Дрисколла *1002* и изменяю / расширяю его для своих собственных целей.

У меня есть три стола (кредиты, люди, карты).Карты к ссуде и Персона к ссуде являются отношениями «один ко многим» и моделируются следующим образом:

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))

Когда я пытаюсь создать новый заем (используя метод, описанный ниже в моем контроллере), он отлично работает дляуникальные карты и люди, но как только я пытаюсь добавить второй кредит для конкретного человека или карты, это дает мне «неуникальную» ошибку.Очевидно, что это не уникально, в этом суть, но я думал, что SQLAlchemy позаботится о закулисных вещах для меня и добавит правильный существующий идентификатор человека или карты в качестве 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()

В примере MediaLocker новые строки создаются с автоматическим приращением PK (даже для дубликатов, не соответствующих правилам нормализации),Я хочу иметь нормализованную базу данных (даже в небольшом проекте, только для лучшей практики в обучении), но не могу найти никаких примеров в Интернете для изучения.

Как мне достичь вышеуказанного?

1 Ответ

5 голосов
/ 08 февраля 2012

Вы должны извлечь и назначить существующий объект Person или Card для отношения, прежде чем пытаться добавить новый объект с повторяющимся первичным ключом. Вы можете сделать это с помощью нескольких небольших изменений в вашем коде.

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()

Есть также несколько решений для get_or_create функций, если вы хотите заключить их в один шаг.

Если вы загружаете большое количество записей в новую базу данных с нуля, и ваш запрос более сложен, чем get (объект сеанса должен кэшировать get поиски самостоятельно), вы можете избежать все запросы осуществляются за счет памяти, добавляя каждый новый объект Person и Card во временный диктант по идентификатору и извлекая из него существующие объекты вместо попадания в базу данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...