SQLAlchemy中的多个自引用关系

时间:2011-02-12 01:49:14

标签: python sqlalchemy

我有一个数据库模型,我需要一对多的关系和两个一对一的关系。这是我制作的模型,但是它会抛出错误

class Page(Base):
    __tablename__ = 'pages'
    id          = Column(Integer, primary_key=True)
    title       = Column(String(100), nullable=False)
    content     = Column(Text, nullable=False)

    parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
    children    = relationship("Page", backref=backref("parent", remote_side=id))

    next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    next        = relationship("Page", backref=backref("prev", remote_side=id, uselist=False))

    prev_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    prev        = relationship("Page", backref=backref("next", remote_side=id, uselist=False))

    def __init__(self, title, content, parent_id=None, next_id=None, prev_id=None):
        self.title = title
        self.content = content
        self.parent_id = parent_id
        self.next_id = next_id
        self.prev_id = prev_id

    def __repr__(self):
        return '<Page "%r">' % self.title

每当我尝试对数据库执行任何操作时,我都会收到以下错误

ArgumentError: Could not determine join condition between parent/child tables on relationship Page.children. Specify a 'primaryjoin' expression. If 'secondary' is present, 'secondaryjoin' is needed as well.

真正奇怪的是它没有下一个和上一个列的工作。有人知道什么是错的吗?

2 个答案:

答案 0 :(得分:14)

这个主题已经过时了,但由于这太令人困惑,我会把它写下来 你不需要单独的'prev'列,你已经将它作为'next'的backref。 此外,由于同一目标有多个外键,因此需要手动指定主连接:

class Page(Base):
    __tablename__ = 'pages'
    id          = Column(Integer, primary_key=True)
    title       = Column(String(100), nullable=False)
    content     = Column(Text, nullable=False)

    parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
    parent      = relationship("Page",
                    primaryjoin=('pages.c.id==pages.c.parent_id'),
                    remote_side='Page.id',
                    backref=backref("children" ))

    next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    next        = relationship("Page", 
                    primaryjoin=('pages.c.next_id==pages.c.id'),
                    remote_side='Page.id', 
                    backref=backref("prev", uselist=False))

我注意到了一些错误或一些奇怪的行为:
- 您只能使用remote_side="Page.id",而不是remote_side=[id]而不是remote_side=["Page.id"],否则它将无效(sqlalchemy 0.6.6)。这很令人讨厌 - 看起来您应始终使用remote_side主键,无论您的实际远程端是什么。即使看起来合适,remote_side="Pages.next_id"也会产生奇怪的错误 - primaryjoin表达式令人困惑,因为它不使用别名,但这实际上是正确的方法。绑定引擎知道要用参数替换哪个表达式(这太隐含了,反对Zen,顺便说一句)。

答案 1 :(得分:1)

您可以使用import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.Scanner; public class FileLoader { public static Reader openReader(String filename, boolean isResource) throws UnsupportedEncodingException, FileNotFoundException, MalformedURLException { return openReader(filename, isResource, "UTF-8"); } public static Reader openReader(String filename, boolean isResource, String charset) throws UnsupportedEncodingException, FileNotFoundException, MalformedURLException { return new InputStreamReader(openInputStream(filename, isResource), charset); } public static InputStream openInputStream(String filename, boolean isResource) throws FileNotFoundException, MalformedURLException { if (isResource) { return FileLoader.class.getClassLoader().getResourceAsStream(filename); } return new FileInputStream(load(filename, isResource)); } public static String read(String path, boolean isResource) throws IOException { return read(path, isResource, "UTF-8"); } public static String read(String path, boolean isResource, String charset) throws IOException { return read(pathToUrl(path, isResource), charset); } @SuppressWarnings("resource") protected static String read(URL url, String charset) throws IOException { return new Scanner(url.openStream(), charset).useDelimiter("\\A").next(); } protected static File load(String path, boolean isResource) throws MalformedURLException { return load(pathToUrl(path, isResource)); } protected static File load(URL url) { try { return new File(url.toURI()); } catch (URISyntaxException e) { return new File(url.getPath()); } } private static final URL pathToUrl(String path, boolean isResource) throws MalformedURLException { if (isResource) { return FileLoader.class.getClassLoader().getResource(path); } return new URL("file:/" + path); } }

foreign_keys