mongoengine default value from another field
Asked Answered
A

3

6

I'm trying out MongoEngine for a project and its quite good. I was wondering if it is possible to set a default value for a field from another field? Something like this

import mongoengine as me

class Company(me.Document):
    short_name = me.StringField(required=True)
    full_name = me.StringField(required=True, default=short_name)

this fails with an error ValidationError (Company:None) (StringField only accepts string values: ['full_name'])

:EDIT:

I did not mention that my app has a service layer which enabled me to simply do it like this:

if company_data['short_name'] is None:
            myCompany.full_name = company_data['short_name']


        obj = myCompany.save()

and it works quite nicely.

Archduchy answered 4/6, 2014 at 18:56 Comment(1)
Mongoengine has a bunch of issues with circular dependencies. It might be possible, but you're probably better off doing this default on your end.Herald
C
11

You can override save() method on a Document:

class Company(me.Document):
    short_name = me.StringField(required=True)
    full_name = me.StringField()

    def save(self, *args, **kwargs):
        if not self.full_name:
            self.full_name = self.short_name

        return super(Company, self).save(*args, **kwargs)
Cloninger answered 4/6, 2014 at 19:4 Comment(4)
Will this execute the rest of the overridden save method, like validation and the actual insert into a collection?Archduchy
@Archduchy yup, it is handled by using super(). Though, better make sure it works for you - I haven't personally tested it.Cloninger
I have tried it like you said and it does insert into the collection but returns None and I am unable to get the _id of the inserted document.Archduchy
@Archduchy my bad, I was missing return statement. Give it another try. Thanks.Cloninger
S
4

Take a look at http://docs.mongoengine.org/guide/defining-documents.html#field-arguments:

You can achieve this by passing a function to default property of the field:

class ExampleFirst(Document):
    # Default an empty list
    values = ListField(IntField(), default=list)

class ExampleSecond(Document):
    # Default a set of values
    values = ListField(IntField(), default=lambda: [1,2,3])

class ExampleDangerous(Document):
    # This can make an .append call to  add values to the default (and all the following objects),
    # instead to just an object
    values = ListField(IntField(), default=[1,2,3])
Spirit answered 27/4, 2017 at 14:49 Comment(1)
Would this work for setting it to the value of another field?Mongolism
B
0

default does not get passed the instance of the document, so you won't be able to achieve what you want.

The save solution is ok, but the value of full_name is not set until there is a save() called.

Instead, use mongoengine's post_init signal

@mongonegine.post_init.connect_via(Company)
def set_full_name(sender, document, **kwargs):
    document.full_name = document.full_name or document.short_name
  • Works for new inits and documents from queries
  • The defaulted value is available immediately after init.
    Company(short_name='hello').full_name' == 'hello'
    
Betony answered 7/8, 2023 at 14:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.