mongoengine icon indicating copy to clipboard operation
mongoengine copied to clipboard

Problem dereferencing non-binary UUID primary keys

Open tudamp opened this issue 10 years ago • 6 comments

Hi all, I have encountered a problem dereferencing instances when that have a primary key that is a UUID that is stored in mongodb as a string.

class Pool(db.Document):
    uuid = db.UUIDField(required=True, primary_key=True, binary=False)

class Host(db.Document):
    uuid = db.UUIDField(required=True, primary_key=True, binary=False )
    pool = db.ReferenceField(Pool)

When I try to access to pool attribute I get a DBRef instance instead a Pool instance.

p = Pool(uuid="36a36f7b-54b7-724f-d28d-2262a629c18a")
h = Host(uuid="70a36f7b-1db7-724f-d28d-2262a629c36b")
h.pool = p
h.save()

host = Host.objects.get(uuid="70a36f7b-1db7-724f-d28d-2262a629c36b")
host.pool
DBRef('pool', UUID('36a36f7b-54b7-724f-d28d-2262a629c18a'))

The DBRef contains the UUID object but the value is stored as string in mongodb. So when this is used in the get of ReferenceField class the search is done using the UUID object instead of the string:

if self._auto_dereference and isinstance(value, DBRef):
    value = self.document_type._get_db().dereference(value)

end return None

If the uuid is stored using binary=True all works fine.

tudamp avatar Mar 25 '15 16:03 tudamp

Ok the problem seems to be in "to_python" of UUID field.

    def to_python(self, value):
        if not self._binary:
            original_value = value
            try:
                if not isinstance(value, basestring):
                    value = unicode(value)
                return uuid.UUID(value)
            except:
                return original_value
        return value

The logic is reversed: if is not binary return a UUID object. Removing the "not" fix it for me.

tudamp avatar Mar 26 '15 10:03 tudamp

nice catch @tudamp !

Would you like to submit a PR with the fix and a test case?

MRigal avatar Apr 29 '15 20:04 MRigal

I've actually tested it and checked a bit the code, it is not that easy.

We have these UUIDField in order to always recreate them as UUID on the Python side and this should NOT be changed.

I don't know actually it we should change it or not, but the problem may rather be in the to_python() method of the ReferenceField class, where we do the following:

        value = DBRef(collection, self.document_type.id.to_python(value))

which indeeds converts it to UUID always. It is the only point I would think to modify, but also I'm not sure.

@tudamp what is actually your problem with the current representation? What operation may you try to do afterwards that fails?

MRigal avatar Jun 17 '15 16:06 MRigal

I have encountered this bug as well using 0.10.5. Is there a workaround for it?

etrochim avatar Jan 20 '16 14:01 etrochim

As far as I checked, this still occurs today with mongoengine==0.28.2

Is there a known workaround for this ?

lordslair avatar May 28 '24 13:05 lordslair

Can confirm this issue still exists in later versions. 0.27 in my case.

ar-qun avatar Mar 25 '25 11:03 ar-qun