Question

I am sure I am missing something, because I cant get Mongoengine/Pyramid to save the embedded document. I have the following:

class Job_history(DynamicEmbeddedDocument):
    job_title = StringField()
    from_ = DateTimeField()
    to_ = DateTimeField()           


class Candidates(Document):

    first_name = StringField(required=True)
    second_name = StringField()
    surname = StringField(required=True)
    id_number = StringField(primary_key=True, required=True)
    id_type = StringField()
    id_nationality = StringField()
    home_number = StringField()
    mobile_number = StringField(required=True)
    email = EmailField(required=True)
    notice_period = StringField()
    date_of_entry = ComplexDateTimeField()
    city_town = StringField()
    province = StringField()
    postal_code = StringField()
    country = StringField()

    job_history = ListField(EmbeddedDocumentField(Job_history))

    meta = {"indexes": ["id_number", "mobile_number", 'province', 'email', 'postal_code']}

When I try to save data to Candidates I get the following error:

ValidationError: ValidationError (Candidates:9109205021082) (Invalid embedded document instance provided to an EmbeddedDocumentField: ['job_history'])
                                              ^    ^    ^
                                       this is the id_number field

I get the data I try to save from an HTML form, I handle this data like this:

@view_config(name='edit', renderer="json", request_method='POST')
    def modify(self):
        params = self.request.params        
        print params
        self.context.first_name = params.get('first_name')
        self.context.second_name = params.get('second_name')
        self.context.surname = params.get('surname')
        self.context.id_number = params.get('id_number')
        self.context.id_type = params.get('id_type')
        self.context.id_nationality = params.get('id_nationality')
        self.context.home_number = params.get('home_number')
        self.context.mobile_number = params.get('mobile_number')
        self.context.email = params.get('email')
        self.context.city_town = params.get('city_town')
        self.context.province = params.get('province')
        self.context.postal_code = params.get('postal_code')
        self.context.country = params.get('country')

        self.context.from_ = params.get("from[]") #embedded document field
        self.context.to_ = params.get("to[]")     #embedded document field
        self.context.industries = params.get("industries[]")    #embedded document field
        can_id = Candidates.objects(id_number=self.context.id_number)

        from_list = []   
        to_list= []     
        job_title_list = []
        industries_list = []
        for k, v in params.iteritems():
            if k == "industries[]":
                industries_list.append(v)
        for k, v in params.iteritems():
            if k == "to[]":
                to_list.append(v)        
        for k, v in params.iteritems():
            if k == "from[]":
                from_list.append(v)
        for k, v in params.iteritems():
            if k == "job_title[]":
                job_title_list.append(v)

        self.context.job_history = [[j,f,t] for j,f,t in zip(job_title_list, from_list, to_list)] # add the embedded document fields into to a list   

        try:
            self.context.save() # try to save to `Candidates`
            print self.context
            self.request.session.flash({"text": "Success!", "type": "success", "heading": "Success"})
        except:            
            self.request.session.flash({"text": "Database error", "type": 'danger', "heading": ""})

        candidate_url = self.request.route_url('candidates', id_number=self.context.id_number, traverse="edit")
        return

The code shown here is shortened.

What am I missing? or what am I doing wrong?

Was it helpful?

Solution

Just going by the api docs on mongoengine. Your schema defines an array of Job_history documents. So rather than creating a list of 3 item tuples from your form input in your list comprehension, just create an instance of Job_history for what the zip function yields.

self.context.job_history = [Job_history(job_title=j, from_=f, to_=t) for j,f,t in zip(job_title_list, from_list, to_list)]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top