<p>如果您的模型确实像您所写的那样简单,那么我将使用<a href="https://docs.sqlalchemy.org/en/14/orm/extensions/associationproxy.html" rel="nofollow noreferrer">Association Proxy</a>来简化这种多对多关系</p>
<p>您的代码将按以下方式更改:</p>
<ul>
<li>添加一个<code>_genre_find_or_create</code>函数:</li>
</ul>
<pre><code>def _genre_find_or_create(category):
obj = Genre.query.filter_by(category=category).first()
return obj or Genre(category=category)
</code></pre>
<ul>
<li>将<code>Movie</code>定义更改为<code>genres</code></li>
</ul>
<pre><code>
class Movie(db.Model):
# ...
_genres = db.relationship(
"Genre",
secondary="association",
backref=db.backref("movies"),
)
genres = association_proxy(
"_genres",
"category",
creator=_genre_find_or_create,
)
</code></pre>
<p>然后您可以按如下方式使用它:</p>
<pre><code># pre-adding data to ensure the category already exists
genre = Genre(category="action")
db.session.add(genre)
db.session.commit()
# adding new data
movie = Movie(title="transformers") # , director="mb")
movie2 = Movie(title="transformers2") # , director="mb")
db.session.add(movie)
db.session.add(movie2)
# OLD way:
# genre = Genre(category="action")
# movie.genres.append(genre)
# movie2.genres.append(genre)
# NEW way: use just 'category'
movie.genres.append("action")
movie2.genres.append("action")
db.session.commit()
</code></pre>
<hr/>
<p><em>另请参见使用此解决方案的另一个<a href="https://stackoverflow.com/a/26103003/99594">question</a></em></p>
<hr/>
<p>我仍然不明白你为什么对<code>DELETE</code>有问题。您的示例代码运行正常,运行时生成以下SQL语句:</p>
<pre><code>DELETE FROM association WHERE association.movies_id = ? AND association.genres_id = ?
DELETE FROM movies WHERE movies.id = ?
</code></pre>
<hr/>
<p><strong>更新:删除</strong>
给定更新的模型,很明显,删除与<code>Movie</code>和<code>Rating</code>之间的一对一关系有关</p>
<p>简单的解决方案是将<code>cascade="delete"</code>添加到<code>Movie.rating</code>关系中,这将在删除<code>Movie</code>的情况下删除与<code>Rating</code>相关的实例:</p>
<pre><code>rating = db.relationship(
"Rating",
uselist=False,
back_populates="movie",
cascade="delete", # <- **NEW**
)
</code></pre>
<p><em>阅读更多关于<a href="https://docs.sqlalchemy.org/en/14/orm/cascades.html" rel="nofollow noreferrer">Cascades</a></em></p>