'ManyToMany relationship using SQLAlchemy

In my pet project I need to send some article to user and log this action with ManyToMany relationship. So, any article can be sent to any user, but only once. After sending we put data to 'sent_log' table with what article_id sent to which user_id.

How do I get (with SQLAlchemy ORM) all articles that is not sent to given user_id? This code doesn't work for me.

def get_user_articles(db: Session, user_telegram_id: int):
"""Get user articles matching language code and user_telegram_id."""
return (
    db.query(models.Article)
    .select_from(join(left=models.Article, right=models.User))
    .filter(models.Article.language_code == models.User.language_code)
    .filter(models.User.telegram_id == user_telegram_id)
    .all()
)

Maybe I've built bad DB structure, guide me than. My models:

sent_log = Table('sent_log', Base.metadata,
                 Column('user_id', ForeignKey('users.id'), primary_key=True),
                 Column('article_id', ForeignKey('articles.id'), primary_key=True)
                 )


class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    telegram_id = Column(Integer, unique=True, index=True)
    username = Column(String(50))
    pet_name = Column(String(50))
    language_code = Column(String(5))

    sent_articles = relationship("Article", secondary=sent_log, back_populates="sent_to_user")


class Article(Base):
    __tablename__ = "articles"

    id = Column(Integer, primary_key=True, index=True)
    text = Column(String(1024))
    image_url = Column(String(500))
    language_code = Column(String(255), index=True)

    sent_to_user = relationship("User", secondary=sent_log, back_populates="sent_articles")


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source