SQLAlchemy等效于Django ORM的跨关系过滤器

4 投票
3 回答
3263 浏览
提问于 2025-04-17 12:11

这个例子来自于Django的文档

假设有一个(Django)数据库模型:

class Blog(models.Model):
    name = models.CharField(max_length=100)

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()

在Django中,我可以使用:

Entry.objects.filter(blog__name__exact='Beatles Blog')

来获取所有指定名称的博客的Entry对象。

问题:根据下面的模型定义,SQLAlchemy中相应的语句是什么?

class Blog(Base):
    __tablename__ = "blog"
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(100))

class Entry(Base):
    __tablename__ = "entry"
    id = Column(Integer, primary_key=True)
    blogid = Column(Integer, ForeignKey(Blog.id))
    headline = Column(Unicode(255))
    body_text = Column(UnicodeText)

    blog = relationship(Blog, backref="entries")

编辑

我认为有两种方法可以做到这一点:

>>> q = session.query
>>> print q(Entry).join(Blog).filter(Blog.name == u"One blog")
SELECT entry.id AS entry_id, entry.blogid AS entry_blogid, entry.headline AS entry_headline, entry.body_text AS entry_body_text 
FROM entry JOIN blog ON blog.id = entry.blogid 
WHERE blog.name = ?

>>> print q(Entry).filter(Entry.blog.has(Blog.name == u"One blog"))
SELECT entry.id AS entry_id, entry.blogid AS entry_blogid, entry.headline AS entry_headline, entry.body_text AS entry_body_text 
FROM entry 
WHERE EXISTS (SELECT 1 
FROM blog 
WHERE blog.id = entry.blogid AND blog.name = ?)

# ... and of course
>>> blog = q(Blog).filter(Blog.name == u"One blog")
>>> q(Entry).filter(Entry.blog == blog)

还有几个问题:

  1. 除了上面提到的方法,还有其他使用SQLAlchemy的方法吗?
  2. 在多对一的关系中,如果你可以这样写session.query(Entry).filter(Entry.blog.name == u"One blog"),这不是很合理吗?
  3. Django的ORM在这种情况下生成的SQL是什么?

3 个回答

1

虽然我来得有点晚,但我偶然发现了这个:
https://github.com/mitsuhiko/sqlalchemy-django-query/blob/master/sqlalchemy_django_query.py

这个东西试图用Django的写法来构建查询。

根据文档的说法: Post.query.filter_by(pub_date__year=2008)

2

我也一直梦想着能有像Django那样的“魔法连接”。我对sqlalchemy-django-query有一些了解,但发现它对我需要做的事情来说功能不够强大。

所以我创建了这个项目

它的工作方式和sqlalchemy-django-query类似,但有更多额外的功能(这里有个对比)。而且它经过了良好的测试,并且文档也写得很清楚。

1

你觉得这样怎么样:

session.query(model.Entry).join((model.Blog, model.Entry.blogid==model.Blog.id)).filter(model.Blog.name=='Beatles Blog').all()

撰写回答