Запрос SQLALCHEMY для связи «многие ко многим» с таблицей карт - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть модель базы данных (см. Ниже). Я работаю над проектом, который должен фильтровать результаты запросов на основе пользовательских категорий - может быть несколько категорий, связанных с пользователем. Другими словами, я хочу показать User с Articles, который соответствует его / ее назначенным категориям. 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 голосов
/ 04 ноября 2018

В обычном m2m у вас есть таблица ассоциации с путем соединения между двумя сущностями, которая четко определена внешними ключами. Таким образом, вы можете просто указать sqlalchemy, какую таблицу вы хотите использовать, чтобы связать две другие таблицы, и она сделает все остальное (как вы сделали здесь: secondary=categories_articles). Присоединение User к Article с немного более сложное.

Вы хотите, чтобы между User и Article существовали отношения "многие ко многим", чтобы вы могли получать статьи, которые интересуют пользователей, на основе общих категорий. Или просто:

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_users объединяется с categories_articles, фактически создавая новую таблицу, в которой строки user объединяются со строками article в их общих категориях. Затем SQLAlchemy может рассматривать это как «нормальное» отношение «многие ко многим» с одной таблицей ассоциации и использовать существующие внешние ключи, чтобы собрать воедино остальные отношения и создать необходимый запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...