SQLALCHEMY查询与映射表的多对多关系

时间:2018-11-04 01:05:05

标签: mysql flask sqlalchemy many-to-many flask-sqlalchemy

我有一个数据库模型(见下文)。我正在研究一个项目,该项目应根据用户分配的类别过滤查询结果-可能有多个与用户相关联的类别。换句话说,我想显示UserArticles匹配的他/她分配的类别。 Articles也可以与多个类别相关联。如何使用sqlalchemy查询实现此目标?

categories_users = db.Table(
    'categories_users',
    db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
    db.Column('category_id', db.Integer(), db.ForeignKey('category.id'))
)

categories_articles = db.Table(
    'categories_articles',
    db.Column('article_id', db.Integer(), db.ForeignKey('article.id')),
    db.Column('category_id', db.Integer(), db.ForeignKey('category.id'))
)

class Category(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    articles = db.relationship('Article', secondary=categories_articles,
        backref=db.backref('categories', lazy='dynamic'))
    def __str__(self):
        return self.name

class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    def __str__(self):
        return self.name

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True, nullable=False)
    categories = db.relationship('Category', secondary=categories_users,
        backref=db.backref('users', lazy='dynamic'))
    def __str__(self):
        return self.email

1 个答案:

答案 0 :(得分:0)

在普通m2m中,您具有一个关联表,该表具有两个实体之间的连接路径,该路径由外键明确定义。这样,您只需告诉sqlalchemy您想要使用哪个表来关联其他两个表,其余的就由它完成(如您在此处所做的操作:secondary=categories_articles)。将UserArticle的连接稍微复杂些。

您希望UserArticle之间存在多对多关系,因此您可以根据常见类别获得用户感兴趣的文章。或者简单地:

User <===> some join path involving categories <===> Article

我们的user表具有categories_users表的外键,而我们的categories_articles表具有articles表的外键。最重要的是,categories_users表和categories_articles表都具有category_id字段,因此我们可以将这两个表连接在一起。

因此,您可以使用以下代码向您的articles模型添加User关系:

articles = db.relationship(
    'Article',
    secondary=\
        'join(categories_users, categories_articles, '
        'categories_users.c.category_id==categories_articles.c.category_id)'
)

访问User.articles属性然后发出此SQL:

SELECT article.id AS article_id, article.name AS article_name
FROM article, categories_users 
INNER JOIN categories_articles 
ON categories_users.category_id = categories_articles.category_id
WHERE %(param_1)s = categories_users.user_id 
AND article.id = categories_articles.article_id

很明显可以看到发生了什么。 categories_userscategories_articles结合在一起,有效地创建了一个新表,其中user行与article行在它们的共同类别上组合在一起。然后,SQLAlchemy可以将其视为具有单个关联表的“正常”多对多关系,并利用现有的外键将其余关系拼凑起来,并构造必要的查询。