Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field where class field name != document field name is not being updated to database #1178

Closed
agani opened this issue Dec 3, 2015 · 1 comment

Comments

@agani
Copy link

agani commented Dec 3, 2015

See the attached for sample code and a dump of the query log.

When I create a field within a class, and that field is bound to a differently named field in the database document (using the db_field option), then updates to that field are not written to the database. The update query does not include that field, although it does include any other fields that need to be written.

The save() method returns a success, and the object instance does have the changes, but the database itself does not.

Examining the query log shows that the updateobj does indeed not have the field with the name 'mismatch', and thus data is not written to the database.

My workaround is to call _mark_as_changed(<name of field in class>) on the document to force this field to be added to the list of fields to be updated.

not_updating.zip

@wojcikstefan
Copy link
Member

wojcikstefan commented Dec 29, 2016

tl;dr when you implement a getter/setter for a field on a mongoengine document, remember that TheDocument.__init__ has to handle kwargs including both the property name and the field name

Not sure if this is a real issue. Your implementation of __init__ is incorrect. Here's the simplified problem of yours:

from mongoengine import *
from datetime import datetime, date, timedelta


class Doc(Document):
    name = StringField(required=True)
    _date_str = StringField(db_field='date_str', required=True)

    def __init__(self, *args, **kwargs):
        rd = kwargs.pop("date", datetime.utcnow())
        super(Doc, self).__init__(*args, **kwargs)
        self._date_str = rd.isoformat()

    @property
    def date(self):
        return self._date_str

    @date.setter
    def date(self, value):
        self._date_str = value.isoformat()

print '='*30
connect('r2d2_local')


today = date.today()
yesterday = today - timedelta(days=1)

Doc.drop_collection()

print 'initialization'
print yesterday
doc = Doc(name='hello', date=yesterday)
print doc._date_str
doc = Doc(name='hello', _date_str=yesterday.isoformat())
print doc._date_str

print 'actual save & reload'
doc = Doc(name='hello', date=yesterday)
doc.save()
doc.reload()
print doc._date_str

It prints:

==============================
initialization
2016-12-28
2016-12-28
2016-12-29T05:21:50.413604
actual save & reload
2016-12-29T05:21:50.415632

So initializing with date works fine, but initializing with _date_str doesn't. When we reload a document, its refreshed version is initialized with _date_str (because that, after all, is the name of the field on the document). If we fix __init__, it works as expected:

from mongoengine import *
from datetime import datetime, date, timedelta


class Doc(Document):
    name = StringField(required=True)
    _date_str = StringField(db_field='date_str', required=True)

    def __init__(self, *args, **kwargs):
        rd = kwargs.pop('date', None)
        super(Doc, self).__init__(*args, **kwargs)
        if rd is not None:
            self._date_str = rd.isoformat()

    @property
    def date(self):
        return self._date_str

    @date.setter
    def date(self, value):
        self._date_str = value.isoformat()

print '='*30
connect('r2d2_local')


today = date.today()
yesterday = today - timedelta(days=1)

Doc.drop_collection()

print 'initialization'
print yesterday
doc = Doc(name='hello', date=yesterday)
print doc._date_str
doc = Doc(name='hello', _date_str=yesterday.isoformat())
print doc._date_str

print 'actual save & reload'
doc = Doc(name='hello', date=yesterday)
doc.save()
doc.reload()
print doc._date_str

Prints correctly:

==============================
initialization
2016-12-28
2016-12-28
2016-12-28
actual save & reload
2016-12-28

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants