SQLAlchemy не может найти связь внешнего ключа с непривилегированным пользователем

У меня есть созданные Django таблицы в базе данных PostgreSQL 8.4, где одна таблица «расширяет» другую. Одна таблица (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, я вижу взаимосвязь в графическом интерфейсе. Я также вижу это с помощью этого оператора, 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_foopayment являются GRANTed SELECT и UPDATE. Я пытался временно предоставить им все разрешения, но безуспешно. Если это имеет значение, последовательность payments_payment_id_seq GRANTed для SELECT и USAGE. Очевидно, что схема foo является GRANTed для USAGE.

Как мне определить отношения вручную в Python или сделать что-то на стороне БД, чтобы самоанализ работал для непривилегированного пользователя?

Подсказки по устранению проблемы также очень приветствуются, так как я полностью потерялся во внутренностях SA.


person drdaeman    schedule 17.02.2011    source источник


Ответы (1)


Вы можете регистрировать запросы SQLAlchemy и сравнивать, что происходит с разными пользователями.

import logging

# Early in your main()
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
logging.getLogger('sqlalchemy.orm').setLevel(logging.INFO)

logging.DEBUG также регистрирует данные ответа.

Насколько я могу судить, для отражения SQLAlchemy использует OID таблицы и запрашивает pg_catalog; ты привел пример. Код находится в SQLAlchemy.dialects.postgresql.base.

Если разрешения для автозагрузки вас огорчают, вы можете объявить отношения в коде примерно так:

class FooPayment(Payment):
    payment_ptr_id = Column(Integer, ForeignKey(Payment.id), primary_key=True)
    payment = relationship(
                  Payment, foreign_keys=[payment_ptr_id], backref='foo_payment')
person Tobu    schedule 21.02.2011
comment
Большое спасибо. Журналы были не очень информативными по сравнению с echo=True (исключение возникает перед тем, как что-либо будет зарегистрировано для FooPayment), но ручное определение помогло. Тем не менее, поскольку я понятия не имею, почему автозагрузка не удалась, я оставлю вопрос открытым на день или два. - person drdaeman; 21.02.2011
comment
Хороший момент, ведение журнала должно быть настроено еще до того, как модели будут импортированы. settings.py — удобное место, если вы все еще используете Django, или у вас может быть main.py, который делает optparse, настраивает логирование и только потом импортирует остальную часть программы. - person Tobu; 22.02.2011