SQLAlchemy 无法找到与非特权用户的外键关系
我在 PostgreSQL 8.4 数据库中有一个 Django 创建的表,其中一个表“扩展”另一个表。一张表 (FooPayment
) 具有主键,该主键引用另一张表 (Payment
)。在 SQL 中,它看起来像这样:
CREATE TABLE foo.payments_payment
(
id integer NOT NULL DEFAULT nextval('payments_payment_id_seq'::regclass),
user_id integer NOT NULL,
...
CONSTRAINT payments_payment_pkey PRIMARY KEY (id),
CONSTRAINT payments_payment_user_id_fkey FOREIGN KEY (user_id)
REFERENCES auth.auth_user (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
CREATE TABLE foo.payments_foopayment
(
payment_ptr_id integer NOT NULL,
...
CONSTRAINT payments_foopayment_pkey PRIMARY KEY (payment_ptr_id),
CONSTRAINT payments_foopayment_payment_ptr_id_fkey FOREIGN KEY (payment_ptr_id)
REFERENCES foo.payments_payment (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
...
)
但是,由于各种原因,我没有使用 Django ORM,并且我正在尝试从 SQLAlchemy 访问表(我使用的是版本 0.6.6,与 pip 一起安装) ):
# Base = declarative_base()
...
class Payment(Base):
__tablename__ = 'payments_payment'
__table_args__ = {'schema': 'foo', 'autoload': True}
user = relation(User, backref='payments')
class FooPayment(Payment):
__tablename__ = 'payments_foopayment'
__table_args__ = {'schema': 'foo', 'autoload': True}
当我以超级用户身份执行此操作时,一切正常。当我作为低特权用户连接时,出现异常:
Traceback (most recent call last):
File "./test.py", line 3, in <module>
from foos import models
File "./foos/models.py", line 127, in <module>
class FooPayment(Payment):
File "lib/python2.6/site-packages/sqlalchemy/ext/declarative.py", line 1167, in __init__
_as_declarative(cls, classname, cls.__dict__)
File "lib/python2.6/site-packages/sqlalchemy/ext/declarative.py", line 1099, in _as_declarative
ignore_nonexistent_tables=True)
File "lib/python2.6/site-packages/sqlalchemy/sql/util.py", line 260, in join_condition
"between '%s' and '%s'.%s" % (a.description, b.description, hint))
sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships between 'payments_payment' and 'payments_foopayment'.
当我作为低特权用户与 PgAdmin3 连接时,我在 GUI 中看到了关系。我还可以用这个语句看到它,SQLAlchemy 本身发出问题:
SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef
FROM pg_catalog.pg_constraint r
WHERE r.conrelid = 16234 AND r.contype = 'f'
ORDER BY 1
它正确返回一行,包含
"payments_foopayment_payment_ptr_id_fkey"; "FOREIGN KEY (payment_ptr_id) REFERENCES payments_payment(id) DEFERRABLE INITIALLY DEFERRED"
至于数据库权限,payments_ payment 和
payments_foo payment 都是
GRANT 编辑了
SELECT
和UPDATE
。我尝试暂时授予他们所有权限,但没有成功。如果这很重要,则会为 SELECT
和 USAGE
授予序列 payment_ payment_id_seq 。显然,模式
foo
已针对 USAGE
进行了 GRANT
编辑。
我应该如何在Python中手动定义关系,或者在数据库端做一些事情,以便内省对非特权用户起作用?
关于调试问题的提示也非常受欢迎,因为我完全迷失在 SA 内部。
I have a Django-created tables in PostgreSQL 8.4 database, where one table "extends" another. One table (FooPayment
) has primary key, which references another table (Payment
). In SQL it looks like this:
CREATE TABLE foo.payments_payment
(
id integer NOT NULL DEFAULT nextval('payments_payment_id_seq'::regclass),
user_id integer NOT NULL,
...
CONSTRAINT payments_payment_pkey PRIMARY KEY (id),
CONSTRAINT payments_payment_user_id_fkey FOREIGN KEY (user_id)
REFERENCES auth.auth_user (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
CREATE TABLE foo.payments_foopayment
(
payment_ptr_id integer NOT NULL,
...
CONSTRAINT payments_foopayment_pkey PRIMARY KEY (payment_ptr_id),
CONSTRAINT payments_foopayment_payment_ptr_id_fkey FOREIGN KEY (payment_ptr_id)
REFERENCES foo.payments_payment (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
...
)
However, I've not to use Django ORM for various reasons, and I'm trying to access the tables from SQLAlchemy (I'm using version 0.6.6, as was installed with pip
):
# Base = declarative_base()
...
class Payment(Base):
__tablename__ = 'payments_payment'
__table_args__ = {'schema': 'foo', 'autoload': True}
user = relation(User, backref='payments')
class FooPayment(Payment):
__tablename__ = 'payments_foopayment'
__table_args__ = {'schema': 'foo', 'autoload': True}
When I'm doing this as superuser, everything works. When I'm connecting as low-privileged user I get an exception:
Traceback (most recent call last):
File "./test.py", line 3, in <module>
from foos import models
File "./foos/models.py", line 127, in <module>
class FooPayment(Payment):
File "lib/python2.6/site-packages/sqlalchemy/ext/declarative.py", line 1167, in __init__
_as_declarative(cls, classname, cls.__dict__)
File "lib/python2.6/site-packages/sqlalchemy/ext/declarative.py", line 1099, in _as_declarative
ignore_nonexistent_tables=True)
File "lib/python2.6/site-packages/sqlalchemy/sql/util.py", line 260, in join_condition
"between '%s' and '%s'.%s" % (a.description, b.description, hint))
sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships between 'payments_payment' and 'payments_foopayment'.
When I'm connecting as this low-privileged user with PgAdmin3, I see the relationship in GUI. I can also see it with this statement, SQLAlchemy issues itself:
SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef
FROM pg_catalog.pg_constraint r
WHERE r.conrelid = 16234 AND r.contype = 'f'
ORDER BY 1
Which properly returns a row, containing
"payments_foopayment_payment_ptr_id_fkey"; "FOREIGN KEY (payment_ptr_id) REFERENCES payments_payment(id) DEFERRABLE INITIALLY DEFERRED"
As for database permissions, both payments_payment
and payments_foopayment
are GRANT
ed SELECT
and UPDATE
. I've tried temporarily granting all permissions on them, without any success. If this matters, a seqence payments_payment_id_seq
is GRANT
ed for SELECT
and USAGE
. Obviously, schema foo
is GRANT
ed for USAGE
.
How should I either define the relationship manually in Python, or do something on DB side, so introspection would work for non-privileged user?
Hints on debugging the problem are also very much welcomed, as I'm completely lost in SA internals.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以记录 SQLAlchemy 的查询,并比较不同用户发生的情况。
logging.DEBUG
还记录响应数据。据我所知,为了反射,SQLAlchemy 使用表 OID 并查询 pg_catalog;你举了一个例子。代码位于
SQLAlchemy.dialects.postgresql.base
中。如果自动加载的权限让您感到悲伤,您可以在代码中声明如下所示的关系:
You can log the queries of SQLAlchemy, and compare what happens with different users.
logging.DEBUG
logs the response data as well.As far as I can tell, for reflection, SQLAlchemy uses table OIDs and queries pg_catalog; you gave an example. The code is in
SQLAlchemy.dialects.postgresql.base
.If the permissions for autoload give you grief, you can declare the relationship in code with something like this: