MongoEngine / MongoEngine/mongoengine

Error with ReferenceField pointing to the abstract document

Open
#2,706 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
4.3k
Forks
1.2k
Avg merge
4h 41m
Merged PRs (30d)
11

Description

We've run into an issue where reload, save, and update throw an error when they dereference the abstract field from a ReferenceField.

It works fine when you initially save the object or get it from the DB but fails if you modify and then save it.

It also works if you use setattr to set the attribute.

Since we use an abstract document, it doesn't exist in the database, so dereference method fails.

Traceback

>>> demo()
Company
456
changed to the second title
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/code/issue.py", line 55, in demo
    issue.reload()  # works
  File "/app/venv/lib/python3.10/site-packages/mongoengine/document.py", line 745, in reload
    self._qs.read_preference(ReadPreference.PRIMARY)
  File "/app/venv/lib/python3.10/site-packages/mongoengine/queryset/base.py", line 844, in select_related
    return queryset._dereference(queryset, max_depth=max_depth)
  File "/app/venv/lib/python3.10/site-packages/mongoengine/dereference.py", line 102, in __call__
    self.object_map = self._fetch_objects(doc_type=doc_type)
  File "/app/venv/lib/python3.10/site-packages/mongoengine/dereference.py", line 197, in _fetch_objects
    references = get_db()[collection].find({"_id": {"$in": refs}})
  File "/app/venv/lib/python3.10/site-packages/pymongo/database.py", line 237, in __getitem__
    return Collection(self, name)
  File "/app/venv/lib/python3.10/site-packages/pymongo/collection.py", line 207, in __init__
    raise TypeError("name must be an instance of str")
TypeError: name must be an instance of str

Example

from mongoengine import StringField, Document, ReferenceField


class Owner(Document):
    meta = {"abstract": True}
    name = StringField()


class Company(Owner):
    # meta = {"strict": False}

    key = StringField()


class Issue(Document):

    title = StringField(required=True)
    owner = ReferenceField(Owner)  # since Owner is the abstract class; it is not registered in the database


def demo():
    company = Company(name="Company", key="456")
    company.save()
    issue = Issue(title="image", owner=company).save()

    print(issue.owner.name)  # prints "Company"
    print(issue.owner.key)  # prints "456"

    setattr(issue, "title", "second title")
    issue.save()
    print("changed to second title")

    issue.reload()  # fails

    # also fails
    issue.text = "another text"
    issue.save()  # fails

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example and trace the failure from mongoengine/document.py through queryset/base.py into dereference.py, especially _fetch_objects. Confirm that reload, save, and update work when a ReferenceField points to an abstract Owner, while preserving the existing setattr behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.