update document with new values in a dictionary

1,038 views
Skip to first unread message

christophe de saint leger

unread,
Jul 10, 2013, 11:20:43 AM7/10/13
to mongoeng...@googlegroups.com
Hi All,

I just want know if it's possible to update document, with a dictionary who contain the new values ?

As exemple


doc = MyDoc(firstname='chrictophe',email='a...@aaa.com')
doc.save()


something :

newData = { 'firstname:'john', 'email':'b...@aaa.com' }
doc.update( **newData )


thank you in advance for your help.

Ch.

Jan Schrewe

unread,
Jul 10, 2013, 11:42:37 AM7/10/13
to mongoeng...@googlegroups.com
No real need for a function a simple for loop will do:

for k, v in newData.items():
    setattr(doc, k, v)
doc.save()


--
You received this message because you are subscribed to the Google Groups "MongoEngine Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mongoengine-us...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

christophe de saint leger

unread,
Jul 10, 2013, 12:08:51 PM7/10/13
to mongoeng...@googlegroups.com
Ok ,

Thanks a lot for your answer .

Regards,

Ch.

Ross Lawley

unread,
Jul 10, 2013, 3:20:30 PM7/10/13
to mongoeng...@googlegroups.com
Or drop into the raw pymongo and nest the dictionary in the $set
--

christophe de saint leger

unread,
Jul 11, 2013, 5:53:33 AM7/11/13
to mongoeng...@googlegroups.com
it's work fine,

but with DBRef type fields, i must to define it, if data is a string id type

ex:

#method gets a dictionary ( POST  form  ) :
data = { 'name':'john','category':'51da83f269ddbb1f0e0738fd'}
#I transform my DBRef Field
data['category'] = DBRef( 'Category', ObjectId( 'category' ))

#Save
for k, v in data.items():
    setattr(doc, k, v)
doc.save()

else document instance return me a "ValidationError"

whereas if I create a new document my id is automatically transformed into DBRef.



Ch.


Le mercredi 10 juillet 2013 17:20:43 UTC+2, christophe de saint leger a écrit :

Laurent Payot

unread,
Jul 11, 2013, 8:25:07 AM7/11/13
to mongoeng...@googlegroups.com
I wouldn't use it but would the code below work too?

doc.__dict__.update(data)
doc.save()



2013/7/11 christophe de saint leger <cdsl....@gmail.com>

--

christophe de saint leger

unread,
Jul 11, 2013, 8:38:02 AM7/11/13
to mongoeng...@googlegroups.com
__dict__ is not a read-only attribute ?

ch.


Le mercredi 10 juillet 2013 17:20:43 UTC+2, christophe de saint leger a écrit :

Laurent Payot

unread,
Jul 11, 2013, 8:50:46 AM7/11/13
to mongoeng...@googlegroups.com
Nope. We're all consenting adults so you can modify it but I wouldn't recommend it if there are safer ways.


2013/7/11 christophe de saint leger <cdsl....@gmail.com>
__dict__ is not a read-only attribute ?

--

Jan Schrewe

unread,
Jul 11, 2013, 8:50:58 AM7/11/13
to mongoeng...@googlegroups.com
Field data is stored in the _data attribute on every document. To just set the data you can just update or overwrite that. Mongoengine does keep track of changes though and tries to do atomic updates. Afaik this is done using __set__() either on the field or on the document itself (not completely sure where and how this is done exactly). So you probably would have to tell the document which fields have been changed. You'd end up with code that is a lot more complicated then the simple for loop and gain just about nothing though. 

If you want to do the conversion for referenced objects automatically you could modify the for loop a bit:

for k, v in data.items():
    field = data._fields[k]
    if isinstance(field, ReferenceField):
        v = DBRef(field.document_type._get_collection_name(), ObjectId(v))
    setattr(doc, k, v)

And no, __dict__ is not read only, Python doesn't really do read only anywhere (except for stuff written by developers who think that Python should behave like Java ;). You should know what you're doing before messing attributes that start with _ or __.


Jan Schrewe

unread,
Jul 11, 2013, 8:57:35 AM7/11/13
to mongoeng...@googlegroups.com
Oh this line 

field = data._fields[k]

should read

field = doc._fields[k]

And as Ross said, you can always use pymongo directly.

christophe de saint leger

unread,
Jul 11, 2013, 9:30:09 AM7/11/13
to mongoeng...@googlegroups.com
ok,
thank you very much for that. :)

My goal is to update my document from fields validated form (Django).

So if I add a field in my form and in my model, I do not need to touch the code that is responsible for modifying the document Mongo.


your method works well  :)

i have added this in my model:

    def update_from_form( self,cleaned_data ):
        """
        Update document, from POST data filtered .
        :param cleaned_data: Dictionnaire filtré, renvoyé par le formulaire
        """
        for k, v in cleaned_data.items():
            if k == '_id' : continue
            field = self._fields[k]

            if isinstance(field, ReferenceField):
                v = DBRef(field.document_type._get_collection_name(), ObjectId(v))
            setattr(self, k, v)
        return self

thank you again.

Ch.


Le mercredi 10 juillet 2013 17:20:43 UTC+2, christophe de saint leger a écrit :

Jan Schrewe

unread,
Jul 11, 2013, 9:42:16 AM7/11/13
to mongoeng...@googlegroups.com
Well, as part of my shameless scheme to advertise my own stuff here, have a look at https://github.com/jschrewe/django-mongodbforms

Does handle even more exception then reference fields ;)


--
Reply all
Reply to author
Forward
0 new messages