我在FASK下使用SQLAlChemy创建了一个Python对象来封装到现有PostgreSQL数据库的链接.我使用反射链接到SQLALCHEMY数据库.

该对象的init代码如下:

    def __init__ (self, app, url) :
        
        app.config ['SQLALCHEMY_DATABASE_URI'] = url
        self.db = SQLAlchemy (app)
        with app.app_context () :
            self.db.reflect ()
            self.md = self.db.metadata
            self.base = automap_base (metadata = self.md)
            self.base.prepare ()

此代码成功加载了一组表,其中包括以下表:

         Column     |           Type           | Collation | Nullable 
     ---------------+--------------------------+-----------+---------
     idlabelstrings | integer                  |           | not null
     category       | character varying(4)     |           |         
     name           | character varying(45)    |           |         
     value          | character varying(16000) |           |         
     locallanguage  | integer                  |           | not null
     owner          | integer                  |           | not null 
    Indexes:
        "localstrings_pkey" PRIMARY KEY, btree (idlabelstrings)
        "localstrings_name_idx" btree (name)
        "localstrings_owner_idx" btree (owner)
    Foreign-key constraints:
        "fk_labelstrings_languages1" FOREIGN KEY (locallanguage) REFERENCES languages(idlanguage)
        "fk_localstrings_owner1" FOREIGN KEY (owner) REFERENCES accounts(idaccounts)

判断数据库元数据表明程序已正确加载外键定义:

    locallanguage   foreign_keys    {ForeignKey('languages.idlanguage')}    <class 'set'>
    owner           foreign_keys    {ForeignKey('accounts.idaccounts')} <class 'set'>

但是,在执行SELECT WITH JOIN时,如下所示:

        dbase = self.db
        localStrings = self.base.classes.localstrings
        accounts = self.base.classes.accounts
        languages = self.base.classes.languages
        select = (dbase.select (localStrings, languages, accounts).
                  join (localStrings.owner).
                  join (localStrings.locallanguage).
                  where (localStrings.category == category))

会产生以下错误:

    2023-10-11 18:59:41,072] ERROR in app: Exception on /liststrings [GET]
    Traceback (most recent call last):
      File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\context.py", line 1792, in _join
        right = right.entity
                ^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 1327, in     __getattr__
        return self._fallback_getattr(key)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 1296, in _fallback_getattr
        raise AttributeError(key)
    AttributeError: entity

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last):
      File "endpoints\venv\Lib\site-packages\flask\app.py", line 2190, in wsgi_app
        response = self.full_dispatch_request()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\flask\app.py", line 1486, in full_dispatch_request
        rv = self.handle_user_exception(e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\flask\app.py", line 1484, in full_dispatch_request
        rv = self.dispatch_request()
             ^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\flask\app.py", line 1469, in dispatch_request
        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\application\app.py", line 124, in stringLister
        result = dataSrc.getStrings ('en', 'wcs', 'public')
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\application\dblink.py", line 92, in getStrings
        return dbase.session.execute (select).scalars () #.mappings ()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\scoping.py", line 738, in execute
        return self._proxied.execute(
               ^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2262, in execute
        return self._execute_internal(
               ^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2144, in _execute_internal
        result: Result[Any] = compile_state_cls.orm_execute_statement(
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\context.py", line 293, in orm_execute_statement
        result = conn.execute(
                 ^^^^^^^^^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1412, in execute
        return meth(
               ^^^^^
      File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\elements.py", line 516, in _execute_on_connection
    return connection._execute_clauseelement(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1627, in _execute_clauseelement
    compiled_sql, extracted_params, cache_hit = elem._compile_w_cache(
                                                ^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\elements.py", line 704, in _compile_w_cache
    compiled_sql = self._compiler(
                   ^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\elements.py", line 316, in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\compiler.py", line 1426, in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\compiler.py", line 867, in __init__
    self.string = self.process(self.statement, **compile_kwargs)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\compiler.py", line 912, in process
    return obj._compiler_dispatch(self, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\visitors.py", line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
           ^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\compiler.py", line 4585, in visit_select
    compile_state = select_stmt._compile_state_factory(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\sql\base.py", line 687, in create_for_statement
    return klass.create_for_statement(statement, compiler, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\context.py", line 1162, in create_for_statement
    self._setup_for_generate()
  File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\context.py", line 1197, in _setup_for_generate
    self._join(query._setup_joins, self._entities)
  File "endpoints\venv\Lib\site-packages\sqlalchemy\orm\context.py", line 1794, in _join
    raise sa_exc.ArgumentError(
    sqlalchemy.exc.ArgumentError: Join target localstrings.owner does not refer to a mapped entity

谁能告诉我为什么SELECT routine 无法将连接列标识为映射实体?

推荐答案

join个子句应该引用ORM类,而不是外键列.

这应该是可行的:

select = (dbase.select (localStrings, languages, accounts).
          join (accounts).
          join (languages).
          where (localStrings.category == category))

生成的SQL如下所示:

SELECT localstrings.idlabelstrings,
       localstrings.category,
       localstrings.locallanguage, 
       localstrings.owner,
       languages.idlanguage, 
       accounts.idaccounts 
  FROM localstrings 
  JOIN accounts 
  ON accounts.idaccounts = localstrings.owner 
  JOIN languages 
  ON languages.idlanguage = localstrings.locallanguage 
  WHERE localstrings.category = ?

SQLAlChemy使用外键定义在查询中创建ON个子句.如果localstrings.ownerlocalstrings.locallanguage没有定义为外键,那么您需要告诉SQLAlChemy如何进行联接:

select = (
    sa.select(localStrings, languages, accounts)
    .join(accounts, localStrings.owner == accounts.idaccounts)
    .join(languages, localStrings.locallanguage == languages.idlanguage)
    .where(localStrings.category == category)
)

最后,请注意,如果自动映射可以检测到它们,则它将为automatically construct relationships,因此您还可以使用这些关系来表示联接:

select = (
    sa.select(localStrings, accounts, languages)
    .join(localStrings.accounts)
    .join(localStrings.languages)
    .where(localStrings.category == category)
)

Postgresql相关问答推荐

使用PGx在围棋中执行多条SQL语句

列不明确

在PostGreSQL中获取最近日期的项目

转到 time.Time to postgresql timestamptz 无法用 time.Now() 保存

如何在 PostgreSQL 的回归测试中测试 TYPE 发送和接收函数

如何在 PostgreSQL 中使用正则表达式删除单词之间的所有特殊字符和多余空格

消除 PostgreSQL SELECT 语句中的重复行

Rails 迁移:PostgreSQL 上的 Bigint 似乎失败了?

使用 try/except 与 psycopg2 或with closing?

将 PostgreSQL 配置为仅适用于 LOCALHOST 或指定的 ip + 端口

psql:致命:connection requires a valid client certificate

IntegrityError:postgres 从转储恢复后,所有具有 ForeignKey 的模型/字段的id列中的空值

我怎样才能知道 Postgresql 表空间中有什么?

Postgis 中 2 点之间的距离,单位为 4326 米

在 postgresql 中,如何在 jsonb 键上返回布尔值而不是字符串?

返回 array_agg() 中的第一个元素

错误:关系列不存在 PostgreSQL,无法运行插入查询

如何将 Heroku PG 转储导入本地机器

学习 PL/pgSQL 的好资源?

如何在 PostgreSQL 中获取数组的最后一个元素?