#๐Ÿ”’ Can't extend many-to-many relationship in sqlalchemy (2nd duplicate)

65 messages ยท Page 1 of 1 (latest)

fickle bobcat
#

Hello! I can't extend many-to-many relationship in sqlalchemy. Here's my code:

async def create_article(session: AsyncSession, topic: TopicEnum,
                          users_ids: List[int], inactive_at: datetime
    ValueModel = create_model('ValueModel', topic=(TopicEnum, ...),
                              inactive_at=(datetime, ...))
    article = await ArticleDAO.add(session=session, values=ValueModel(topic=topic,
                                                                 inactive_at=inactive_at))
    users = await UserDAO.find_all(session=session, filters=None, filter_lmbd=lambda a: a.id in users_ids)
    await article.liked_by.extend(users)

Full error is in the attachment. What am I doing wrong? From the previous answers I got that I need to do it asynchronously, but it seems like I can't. I want to extend the relationship, add new users to it. When I try to access it via awaitable_attrs it throws coroutine has no method called extend(), and when I separate it into another variable and call extend on that it throws object of NoneType has no method called extend(). I don't have any lazy loading here afaik (I might be wrong). I know the primary keys of models I want to add to the relationship and the model that has that relationship. Can someone tell me the way to do it properly?

pallid sageBOT
#

@fickle bobcat

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

whole token
fickle bobcat
whole token
#

can you show the implementation?

fickle bobcat
#

Article.liked_by is a many-to-many relationship to User class of type List[User]

fickle bobcat
# whole token can you show the implementation?
async def add(self, session: AsyncSession, values: BaseModel):
            values_dict = values.model_dump(exclude_unset=True)
            new_instance = Article(**values_dict)
            session.add(new_instance)
            try:
                await session.flush()
            except SQLAlchemyError as e:
                await session.rollback()
                raise e
            return new_instance
whole token
fickle bobcat
#

Like full class?

whole token
#

Oh, it doesn't return an instance of ArticleDAO

fickle bobcat
#

Yeah

whole token
fickle bobcat
#
class Base(AsyncAttrs, DeclarativeBase):
    __abstract__ = True

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    created_at: Mapped[datetime] = mapped_column(server_default=func.now())


association_table = Table(
    "association_table",
    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'

    full_name: Mapped[str] = mapped_column(String(50))
    liked_articles: Mapped[List["Article"]] = relationship(
        secondary=association_table, back_populates="liked_by"
    )
    role: Mapped[RoleEnum]
    is_admin: Mapped[bool]

class Article(Base):
    __tablename__ = 'articles'

    topic: Mapped[TopicEnum]
    liked_by: Mapped[List["User"]] = relationship(
        secondary=association_table, back_populates="liked_articles"
    )
    inactive_at: Mapped[datetime]
fickle bobcat
#

I don't get what's wrong here

whole token
#

from this File "d:\Python projects\testbot\database\controller.py", line 254, in create_article await article.liked_by.extend(users) ^^^^^^^^^^^^^^ it looks like the error happens when accessing the liked_by attribute

fickle bobcat
#

Yes

whole token
#

so if you just do print(article.liked_by), you should get the same error

fickle bobcat
#

Calling awaitable_attrs introduce another errors

fickle bobcat
#

Yes, you are right

whole token
#

In synchronous SQLAlchemy, article.liked_by potentially does an actual SQL query, so it makes sense that this doesn't work in the asyncio mode on its own

fickle bobcat
#

Yes

#

For that they recommend to use awaitable_attrs

whole token
#

oh, it is using AsyncAttrs

fickle bobcat
#

article.awaitable_attrs.liked_by.extend(users)

#

It says coroutine object has no method called extend()

#

Okay, I tried to change

whole token
#

Right, liked_by is a list, it does not have any async methods

fickle bobcat
#
article_users = article.awaitable_attrs.liked_by
article_users.extend(users)
#

Object of type NoneType has no method called extend()

whole token
#

Can you show the traceback?

fickle bobcat
whole token
#

yes

#

and the new code

fickle bobcat
pallid sageBOT
whole token
#

right, extend on a list returns None

#

the actual I/O will be performed, in both normal and async mode, after you commit the session

fickle bobcat
#
    ValueModel = create_model('ValueModel', topic=(TopicEnum, ...),
                              inactive_at=(datetime, ...))
    article = await ArticleDAO.add(session=session, values=ValueModel(topic=topic,
                                                                 inactive_at=inactive_at))
    users = await UserDAO.find_all(session=session, filters=None, filter_lmbd=lambda a: a.id in users_ids)
    article_users = await article.awaitable_attrs.liked_by
    await article_tasks.extend(users)
fickle bobcat
#

So what do I need?

#

Commit in the middle of transaction?

whole token
#

Well, eventually the session will be committed

fickle bobcat
#

Yes

#

I/O will be performed

#

But it doesn't happen

#

Why is there an error

#

It should be ok

#

Yes

whole token
fickle bobcat
#

Docs do exactly as I was doing in my first attempt

whole token
#

You should be able to use extend, but you can't use await in front of it

fickle bobcat
#

It seems like it's working

#

But there's one thing

#

For some reason liked_by is empty after commit

#

But I guess that's another issue

#

And the original one is solved

#

Thanks for help!

#

!solved

pallid sageBOT
#
Python help channel closed with !close

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.