回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p><strong><em>请查看底部的更新</em></strong></p>
<p>我有三节课。我们把它们称为<code>Post</code>,<code>PostVersion</code>,和{<cd3>}。(这是针对web应用中的内部版本控制系统,可能类似于StackOverflow,不过我不确定它们的实现策略)。我用git的术语来理解它。为了这个问题的目的,这些是类的高度简化版本:</p>
<pre><code>class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
author = db.relationship("User", backref="posts")
head_id = db.Column(db.Integer, db.ForeignKey("post_version.id"))
HEAD = db.relationship("PostVersion", foreign_keys=[head_id])
added = db.Column(db.DateTime, default=datetime.utcnow)
class PostVersion(db.Model):
id = db.Column(db.Integer, primary_key=True)
editor_id = db.Column(db.Integer, db.ForeignKey("user.id"))
editor = db.relationship("User")
previous_id = db.Column(db.Integer, db.ForeignKey("post_version.id"), default=None)
previous = db.relationship("PostVersion")
pointer_id = db.Column(db.Integer, db.ForeignKey("post.id"))
pointer = db.relationship("Post", foreign_keys=[pointer_id])
post = db.Column(db.Text)
modified = db.Column(db.DateTime, default=datetime.utcnow)
tag_1_id = db.Column(db.Integer, db.ForeignKey("tag.id"), default=None)
tag_2_id = db.Column(db.Integer, db.ForeignKey("tag.id"), default=None)
tag_3_id = db.Column(db.Integer, db.ForeignKey("tag.id"), default=None)
tag_4_id = db.Column(db.Integer, db.ForeignKey("tag.id"), default=None)
tag_5_id = db.Column(db.Integer, db.ForeignKey("tag.id"), default=None)
tag_1 = db.relationship("Tag", foreign_keys=[tag_1_id])
tag_2 = db.relationship("Tag", foreign_keys=[tag_2_id])
tag_3 = db.relationship("Tag", foreign_keys=[tag_3_id])
tag_4 = db.relationship("Tag", foreign_keys=[tag_4_id])
tag_5 = db.relationship("Tag", foreign_keys=[tag_5_id])
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
tag = db.Column(db.String(128))
</code></pre>
<p>为了创建一个新的post,我创建了一个post和一个<code>PostVersion</code>指向的初始<code>Post.head_id</code>。每次进行编辑时,都会创建一个指向上一个<code>PostVersion</code>的新的<code>PostVersion</code>,而{<cd5>}则重置为指向新的<code>PostVersion</code>。要将post版本重置为早期版本——嗯,我还没有走到那么远,但是复制以前的版本或只是将指针重置到以前的版本似乎很简单。在</p>
<p>不过,我的问题是:如何编写<code>Post</code>和{<cd3>}之间的关系,使之</p>
<ol>
<li><code>Post.tags</code>将是当前{<cd2>}包含的所有标记的列表,并且</li>
<li><code>Tag.posts</code>将是当前具有该特定标记的所有{<cd1>}的列表?在</li>
</ol>
<p>第一个条件似乎很简单,一个简单的方法</p>
^{pr2}$
<p>这个技巧暂时还可以,但第二个条件现在对我来说几乎是棘手的。我目前在Tag中使用了一种令人讨厌的方法,我使用一个<code>or_</code>过滤器查询带有该标记的所有<code>PostVersion</code>:</p>
^{3}$
<p>这是非常低效的,我不能分页的结果。在</p>
<p>我知道这将是从<code>Post</code>到<code>Tag</code>或{<cd3>}到{<cd1>}到{<cd2>}的二次连接,但它必须是or上的二次连接,我甚至不知道如何开始编写它。在</p>
<p>回顾我的代码,我开始想知道为什么有些关系需要定义<code>foreign_keys</code>参数,而另一些则不需要。我认为这与它们的定义位置有关(是否紧跟在FK id列之后),并注意到有一个<code>foreign_keys</code>的列表,我在想<em>这就是我应该如何定义的它。但我不知道该怎么做。在</p>
<p>我现在还想知道是否可以用一个配置良好的关系来免除<code>pointer_id</code>上的<code>PostVersion</code>。然而,这与问题无关(尽管循环引用确实会引起头痛)。在</p>
<p>作为参考,我使用了Flask SQLAlchemy、Flask migrate和MariaDB。我非常关注<a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" rel="nofollow noreferrer">Miguel Grinberg's Flask Megatutorial</a>。在</p>
<p>任何帮助或建议都是天赐之物。在</p>
<h2>更新</h2>
<p>我设计了以下mysql查询,它的工作原理是<em>,现在我需要将其转换为sqlalchemy:</p>
<pre><code>SELECT
post.id, tag.tag
FROM
post
INNER JOIN
post_version
ON
post.head_id=post_version.id
INNER JOIN
tag
ON
post_version.tag_1_id=tag.id OR
post_version.tag_2_id=tag.id OR
post_version.tag_3_id=tag.id OR
post_version.tag_4_id=tag.id OR
post_version.tag_5_id=tag.id OR
WHERE
tag.tag="<tag name>";
</code></pre>