BeanieODM / beanie

Asynchronous Python ODM for MongoDB
http://beanie-odm.dev/
Apache License 2.0
2.04k stars 215 forks source link

[BUG] Issue with fetch links w/pydantic v2 #663

Open dammianhr opened 1 year ago

dammianhr commented 1 year ago

Hello,

I hope this message finds you well. I'd like to report an issue I encountered while using the Beanie library in Python. In the context of fetching links (relationships), I've noticed that the fetch_links=True parameter is not functioning as expected in the find, find_one, and get methods.

Specifically, in objects inherited from the 'Document' class, the fetch_all_links() and fetch_link('field') methods exist. However, the latter (fetch_link) seems to be the only one working as intended, but it only retrieves the relationship for a single field.

Here are the library versions I'm using:

pydantic == 2.2.0
beanie == 1.21.0
pymongo == 4.4.1
motor == 3.2.0

I appreciate your time and assistance in addressing this issue. Thank you for your support.

Best regards,

UPDATE: the problem occurs when the attribute is nullable:

class DBObject(Document): internal_notes: list[Link[InternalNotes]] | None = []

roman-right commented 1 year ago

Hi! I'll try to reproduce this today. Thank you for the report

roman-right commented 1 year ago

Hi @dammianhr , Sorry for the late reply. Could you please provide a single module example, which I can run to reproduce? I can not reproduce it.

MrEarle commented 1 year ago

I got the same problem. But only with a nullable link list using the pipe operator. I encountered this with fetch_all_links.

Small example of my code:

# Does not work:
class MyDocument(Document):
  author: Link[User]
  coauthors: list[Link[User]] | None

my_document = MyDocument(...).create()
await my_document.fetch_all_links()  # Only fetches author
my_document.get_link_fields()  # returns { "author": (...) }

# Works:
class MyDocument(Document):
  author: Link[User]
  coauthors: Optional[list[Link[User]]]

my_document = MyDocument(...).create()
await my_document.fetch_all_links()  # Fetches everything as expected
my_document.get_link_fields()  # returns { "author": (...), "coauthor": (...) }

I believe the issue is when defining the instance's _link_fields attribute, since my_document.get_link_fields() returned a dictionary with only "author" in the first case, and with "author" and "coauthors" in the second example.

Edit: I'm using:

beanie = "~1.21"
pydantic = "~1.10"

Haven't tested it with Pydantic 2