Как сделать запрос составного цикла с объединением в MSQLAlchemy (Postgres) (Python) - PullRequest
0 голосов
/ 07 декабря 2018

Хорошо, пожалуйста, потерпите меня, поскольку я новичок в SQLAlchemy и Postgres.У меня есть следующие модели: Lead, Keyword и User.

Я создал много-много взаимосвязей между потенциальными клиентами и ключевыми словами, например:

keyword_identifier = db.Table(
    'keyword_identifier',
    db.Column('lead_id', db.Integer, db.ForeignKey('leads.id')),
    db.Column('keyword_id', db.Integer, db.ForeignKey('keywords.id'))
)

И у моего пользователя у меня есть свойство с именемключевые слова, который является массивом с идентификатором ключевых слов в нем.

Теперь мне нужно найти все потенциальные клиенты, связанные с идентификатором ключевых слов, присутствующим в списке user.keywords.

Я пыталсяследующее:

leads = Lead.query.join(keyword_identifier).join(Keyword).filter(keyword_identifier.c.lead_id.in_([k for k in u.keywords]))

, который приносит только 2 результата (я знаю, что только одно из ключевых слов было связано с более чем 2000 отведениями, поэтому определенно не правильно).

У меня также естьпопробовал:

for keyword_id in user.keywords:
    leads = Lead.query.join(keyword_identifier).join(Keyword).filter(keyword_identifier.c.lead_id == keyword_id)

Но это тоже не дает правильных результатов.

Кто-нибудь может порекомендовать, какой подход будет лучшим здесь?

1 Ответ

0 голосов
/ 07 декабря 2018

Я изменил мини-пример с тем же макетом базы данных: книга связана с одним пользователем (один ко многим), и в книге много слов, и слова могут появляться в нескольких книгах (от многих ко многим).Чтобы получить все слова для всех книг, связанных с пользователем, используйте этот запрос:

Word.query.join(Word, Book.words).filter(Book.user_id==1).all()

Таким образом, чтобы перевести его на ваш пример, это будет что-то вроде:

Lead.query.join(Lead, Keyword.leads).filter(Keyword.user_id==1234).all()

Полный пример:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy, BaseQuery

app = Flask(__name__)
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    books = db.relationship('Book', backref='user')

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    words = db.relationship('Word', secondary='book_to_word_junction', lazy='subquery',
        backref=db.backref('book', lazy=True))

class Word(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)

keyword_identifier = db.Table(
    'book_to_word_junction',
    db.Column('book_id', db.Integer, db.ForeignKey('book.id')),
    db.Column('word_id', db.Integer, db.ForeignKey('word.id'))
)

db.create_all()

def add_db_samples():
    dummy_data = {
        'user1@email.com': {
            'harry potter': ['yer', 'a', 'wizard', 'herry', 'no', 'way', 'hagrid'],
            'egg cookbook': ['a', 'recipe', 'for', 'scrambled', 'eggs', 'no', 'really', 'yummy', 'eggs']
        },
        'user2@email.com': {
            'da vinci code': ['some', 'action', 'some', 'romance']
        }
    }


    for email in dummy_data:
        user = User()
        for title in dummy_data[email]:
            book = Book(title=title)
            for word_name in dummy_data[email][title]:
                word = Word.query.filter_by(name=word_name).first()
                if not word:
                    word = Word(name=word_name)
                book.words.append(word)
                db.session.add(word)
                db.session.commit()
            user.books.append(book)
        db.session.add(user)
    db.session.commit()

add_db_samples()

print(Word.query.join(Word, Book.words).filter(Book.user_id==1).all())

Редактировать:

относительно вашего комментария, вы используете in_(), как вы обычно делаете на этапе фильтрации:

Word.query.join(Word, Book.words).filter(Book.user_id.in_([1,2])).all()

Lead.query.join(Lead, Keyword.leads).filter(Keyword.user_id.in_([1, 2])).all()
...