SQLalchemy查找id并使用它来查找其他信息

时间:2016-09-28 03:35:29

标签: python sqlalchemy

我正在为日文字符(汉字)创建一个简单的查找应用程序,用户可以使用任何可用信息搜索数据库。

我的数据库结构

汉字

  • ID
  • 字符(像顽A一样的汉字)
  • heisig6(表示显示汉字的顺序的数字)
  • kanjiorigin(表示显示汉字的顺序的数字)

含义EN (1个kanji_id可以有多个具有不同含义的条目):

  • kanji_id(FOREIGN KEY(kanji_id)REFERENCES“Kanji”(id)
  • 含义

用户处理

用户可以选择按“id”,“character”,“heisig6”,“kanjiorigin”或“含义”进行搜索,然后它应该返回所有这些字段中的所有信息。 (所有字段只返回1个结果,但含义除外,它可以返回多个结果)

Code,EDIT 4 + 5:我的代码感谢@ApolloFortyNine和IRC上的#sqlalchemy,编辑6:join - > outerjoin(否则将找不到没有起源的信息)

import sqlalchemy as sqla
import sqlalchemy.orm as sqlo
from tableclass import TableKanji, TableMeaningEN, TableMisc, TableOriginKanji  # See tableclass.py

# Searches database with argument search method
class SearchDatabase():
    def __init__(self):
        #self.db_name = "sqlite:///Kanji_story.db"
        self.engine = sqla.create_engine("sqlite:///Kanji.db", echo=True)

        # Bind the engine to the metadata of the Base class so that the
        # declaratives can be accessed through a DBSession instance
        tc.sqla_base.metadata.bind = self.engine

        # For making sessions to connect to db
        self.db_session = sqlo.sessionmaker(bind=self.engine)

    def retrieve(self, s_input, s_method):
        # s_input: search input
        # s_method: search method
        print("\nRetrieving results with input: {} and method: {}".format(s_input, s_method))

        data = []  # Data to return

        # User searches on non-empty string
        if s_input:
            session = self.db_session()

            # Find id in other table than Kanji
            if s_method == 'meaning':
                s_table = TableMeaningEN  # 'MeaningEN'
            elif s_method == 'okanji':
                s_table = TableOriginKanji  # 'OriginKanji'
            else:
                s_table = TableKanji  # 'Kanji'

            result = session.query(TableKanji).outerjoin(TableMeaningEN).outerjoin(
                (TableOriginKanji, TableKanji.origin_kanji)
            ).filter(getattr(s_table, s_method) == s_input).all()
            print("result: {}".format(result))
            for r in result:
                print("r: {}".format(r))

                meanings = [m.meaning for m in r.meaning_en]
                print(meanings)
                # TODO transform into origin kanji's
                origins = [str(o.okanji_id) for o in r.okanji_id]
                print(origins)

                data.append({'character': r.character, 'meanings': meanings,
                             'indexes': [r.id, r.heisig6, r.kanjiorigin], 'origins': origins})

            session.close()

        if not data:
            data = [{'character': 'X', 'meanings': ['invalid', 'search', 'result']}]
        return(data)

问题编辑4 + 5

  • 这是一个有效的查询吗?:result = session.query(TableKanji).join(TableMeaningEN).filter(getattr(s_table, s_method) == s_input).all()(.join语句是必要的,因为否则例如session.query(TableKanji).filter(TableMeaningEN.meaning == 'love').all()由于某种原因返回我数据库中的所有含义?所以这是正确查询或我的tableclass.py中的relationship()未正确定义?

  • 已修复(请参阅tableclass.py中的lambda:kanji = relationship("TableKanji", foreign_keys=[kanji_id], back_populates="OriginKanji")< - 有什么问题?它给出了错误:

    文件“/path/python3.5/site-packages/sqlalchemy/orm/mapper.py”,第1805行,在get_property中  “Mapper'%s'没有属性'%s'”%(自我,键))

    sqlalchemy.exc.InvalidRequestError:Mapper'Mapper | TableKanji | Kanji'没有属性'OriginKanji'

编辑2:tableclass.py(编辑3 + 4 + 5:更新)

import sqlalchemy as sqla
from sqlalchemy.orm import relationship
import sqlalchemy.ext.declarative as sqld

sqla_base = sqld.declarative_base()


class TableKanji(sqla_base):
    __tablename__ = 'Kanji'

    id = sqla.Column(sqla.Integer, primary_key=True)
    character = sqla.Column(sqla.String, nullable=False)
    radical = sqla.Column(sqla.Integer)  # Can be defined as Boolean
    heisig6 = sqla.Column(sqla.Integer, unique=True, nullable=True)
    kanjiorigin = sqla.Column(sqla.Integer, unique=True, nullable=True)
    cjk = sqla.Column(sqla.String, unique=True, nullable=True)

    meaning_en = relationship("TableMeaningEN", back_populates="kanji")  # backref="Kanji")
    okanji_id = relationship("TableOriginKanji", foreign_keys=lambda: TableOriginKanji.kanji_id, back_populates="kanji")

class TableMeaningEN(sqla_base):
    __tablename__ = 'MeaningEN'

    kanji_id = sqla.Column(sqla.Integer, sqla.ForeignKey('Kanji.id'), primary_key=True)
    meaning = sqla.Column(sqla.String, primary_key=True)

    kanji = relationship("TableKanji", back_populates="meaning_en")


class TableOriginKanji(sqla_base):
    __tablename__ = 'OriginKanji'

    kanji_id = sqla.Column(sqla.Integer, sqla.ForeignKey('Kanji.id'), primary_key=True)
    okanji_id = sqla.Column(sqla.Integer, sqla.ForeignKey('Kanji.id'), primary_key=True)
    order = sqla.Column(sqla.Integer)

    #okanji = relationship("TableKanji", foreign_keys=[kanji_id], backref="okanji")
    kanji = relationship("TableKanji", foreign_keys=[kanji_id], back_populates="okanji_id")

1 个答案:

答案 0 :(得分:1)

我们真的必须能够看到你的数据库模式给出真正的批评,但假设没有外键,你所说的基本上是你能做的最好的。

当你复杂的关系发生时,SQLAlchemy真的开始闪耀。例如,如果您正确设置了外键,则可以执行以下操作。

# Assuming kanji is a tc.tableMeaningEN.kanji_id object
kanji_meaning = kanji.meanings

这会将汉字的含义作为一个数组返回,而无需进一步查询。

你可以深入了解关系,所以我在这里链接文档。 http://docs.sqlalchemy.org/en/latest/orm/relationships.html

编辑:实际上,您根本不需要手动加入,SQLAlchemy会为您完成。

你的课程案例有误,但我不确定SQLAlchemy是否区分大小写。如果有效,那就继续前进。

如果查询表(self.session.query(User).filter(User.username == self.name).first()),则应该有一个表类型的对象(User here)。 / p>

因此,在您的情况下,单独查询TableKanji表将返回该类型的对象。

kanji_obj = session.query(TableKanji).filter(TableKanji.id == id).first()
# This will return an array of all meaning_ens that match the foreign key
meaning_arr = kanji_obj.meaning_en
# This will return a single meeting, just to show each member of the arr is of type TableMeaningEn
meaning_arr[0].meaning

我有一个项目使用了其中的一些功能,希望它有所帮助: https://github.com/ApolloFortyNine/SongSense 数据库声明(带关系):https://github.com/ApolloFortyNine/SongSense/blob/master/songsense/database.py 自动加入:https://github.com/ApolloFortyNine/SongSense/blob/master/songsense/getfriend.py#L134

我非常喜欢我的数据库结构,但至于其余部分,它非常糟糕。希望它仍然有用。