How to Update Records with Wizard?

Dear Tryton Community,

How to Update Records with Wizard?

Trying to make our first Wizard.

We have a model to which we want to update data using Wizard.
The model contains several fields, the records were written in another form.
The Wizard is required to manage the records.

The Wizard is invoked from a button called from a form which contains an existing record.
The Wizard creates a new form with a field to enter information (type: fields…Text) and with two buttons called and .

It is expected that a click on the “save” button will save the form data in the model of the existing record.


Difficulty:

  • Clicking the “save” button in the Wizard does not save the records.
  • How to write correctly the call code of the record fields?

Error:

  • The function write() is not receiving the necessary parameters.
 TypeError: write() missing 1 required positional argument: 'values
  • When we replace the write() function with the save() function, it lets the parameters pass, but requests fields from the existing record, previously entered

ENVIRONMENT:

  • OS: Ubuntu 20.04.1 LTS
  • Python: 3.8.5
  • Trytond: 5.8.1
  • Tryton: 5.8.1
  • Module: 5.8
  • Postgresql: 12.5

CODE:

Please check our wizard code:

 class wizard(Wizard): 
   'Wizard'
   __name__ = 'wizard'
   start_state = 'parameters'
   parameters = StateView(
       'model.name.parameters',
       'model.name_view_form', [
           Button('Cancelar', 'end', 'tryton-cancel'),
           Button('Guardar', 'save', 'tryton-forward', default=True)
       ])
   save = StateTransition()
   open_incidents = StateAction('model.act_name_list')

def default_parameters(self, name):
       Model = Pool().get('model_name')
       model = Model.browse(Transaction().context.get('active_id')) # extraer el modelo
       return model, {
           'field_date': datetime.datetime.today(),
           'field_state': 'closed',
           'field_sub_state': 'new_closed',
       } # Valores del formulario del wizard que se van a actualizar en el registro
 
def transition_save(self, model):
       to_update = []
       field_date = self.parameters.field_date
       field_summary = self.parameters.field_summary
       state = self.parameters.field_state
       sub_state = self.parameters.field_sub_state
       to_update.append(
           model(field_date=field_date,
                     field_summary=field_summary,
                     field_state=state,
                     field_sub_state=sub_state,
                     ))
       model.write(to_update)
       return 'end'
 
class parameters (ModelView):
	‘Parameters’
	__name__ = ‘wizard.parameters’
	field_summary = fields.Text
	field_date = fields.DateTime
	field_state = fields.Selection
	field_sub_state = fields.Selection

We are just recognizing this wonderful Tryton.
Appreciate all your valuable help !!

Any comment welcome.

Our native language version:

Intentando hacer nuestro primer Wizard.

Tenemos un modelo al que se quiere actualizar datos usando Wizard.
El modelo contiene varios campos, los registros fueron escritos en otro formulario.
Se requiere que el Wizard gestione los registros.

El Wizard se invoca desde un botón llamado desde un formulario el cual contiene un registro existente.
El Wizard crea un nuevo formulario con un campo para ingresar información (tipo: fields…Text) y con dos botones llamados y .

Se espera que un clic en el botón “save” guarde los datos del formulario en el modelo del registro existente.


Dificultad:

  • Dar clic al botón “save” del Wizard No guarda los registros.
  • Cómo escribir correctamente el código de llamado de los campos del registro?

Error:

  • La función write() no está recibiendo los parámetros necesarios.
 TypeError: write() missing 1 required positional argument: 'values'
  • Cuando sustituimos la función write() por la función save() deja pasar los parámetros, pero solicita campos del registro existente, ingresado previamente

ENTORNO:

  • OS: Ubuntu 20.04.1 LTS
  • Python: 3.8.5
  • Trytond: 5.8.1
  • Tryton: 5.8.1
  • Module: 5.8
  • Postgresql: 12.5

CÓDIGO:

Por favor revisar nuestro código del wizard:

 class wizard(Wizard): 
   'Wizard'
   __name__ = 'wizard'
   start_state = 'parameters'
   parameters = StateView(
       'model.name.parameters',
       'model.name_view_form', [
           Button('Cancelar', 'end', 'tryton-cancel'),
           Button('Guardar', 'save', 'tryton-forward', default=True)
       ])
   save = StateTransition()
   open_incidents = StateAction('model.act_name_list')

def default_parameters(self, name):
       Model = Pool().get('model_name')
       model = Model.browse(Transaction().context.get('active_id')) # extraer el modelo
       return model, {
           'field_date': datetime.datetime.today(),
           'field_state': 'closed',
           'field_sub_state': 'new_closed',
       } # Valores del formulario del wizard que se van a actualizar en el registro
 
def transition_save(self, model):
       to_update = []
       field_date = self.parameters.field_date
       field_summary = self.parameters.field_summary
       state = self.parameters.field_state
       sub_state = self.parameters.field_sub_state
       to_update.append(
           model(field_date=field_date,
                     field_summary=field_summary,
                     field_state=state,
                     field_sub_state=sub_state,
                     ))
       model.write(to_update)
       return 'end'
 
class parameters (ModelView):
	‘Parameters’
	__name__ = ‘wizard.parameters’
	field_summary = fields.Text
	field_date = fields.DateTime
	field_state = fields.Selection
	field_sub_state = fields.Selection
 

Apenas estamos reconociendo este maravilloso Tryton, Apreciamos toda su valiosa ayuda.

The default_ should not return instances only a dictionary for the fields passed as parameter.

The transition_ method does not take any parameter.

The ModelSQL.write method is the low level API which requires as parameters a list of instances and a dictionary of value.

The ModelStorage.save is a dualmethod which can be used on an instance to save the modified attributes or as a classmethod with a list of instances to save all of them at once.

The transition method should look like

def transition_save(self):
    pool = Pool()
    Model = pool.get('model_name')
    record = Model(Transaction().context['active_id'])
    record.field_date = self.parameters.field_date
    …
    record.save()
    return 'end'

In version >= 5.8, you can even write:

def transition_save(self):
    self.record.field_date = self.parameters.field_date
    …
    self.record.save()
    return 'end'

Thanks @ced for the answer, it helps to understand the basics.
When making corrections the following error appears:

Traceback (most recent call last):
  File "/trytond/wsgi.py", line 111, in dispatch_request
	return endpoint(request, **request.view_args)
  File "/trytond/protocols/dispatcher.py", line 47, in rpc
	return methods.get(request.rpc_method, _dispatch)(
  File "/trytond/wsgi.py", line 78, in auth_required
	return wrapped(*args, **kwargs)
  File "/trytond/protocols/wrappers.py", line 131, in wrapper
	return func(request, pool, *args, **kwargs)
  File "/trytond/protocols/dispatcher.py", line 181, in _dispatch
	result = rpc.result(meth(*c_args, **c_kwargs))
  File "/trytond/wizard/wizard.py", line 314, in execute
	return wizard._execute(state_name)
  File "/trytond/wizard/wizard.py", line 345, in _execute
	result = self._execute(transition())
  File "/incidents.py", line 749, in transition_save
	incidence.closing_date = self.parameters.closing_date
AttributeError: 'list' object has no attribute 'closing_date'

Fault: 'list' object has no attribute 'closing_date'

Implementing your instructions, our updated code:

start_state = 'parameters'
   parameters = StateView(
       'incidents.manage_incidents.parameters',
       'incidents.manage_incidents_parameters_view_form', [
           Button('Cancelar', 'end', 'tryton-cancel'),
           Button('Guardar', 'save', 'tryton-forward', default=True)
       ])
   save = StateTransition()
   open_incidents = StateAction('incidents.act_state_opens_list')

   def default_parameters(self, name):
       return {
           'closing_date': datetime.datetime.today(),
           'state': 'closed',
           'sub_state': 'new_closed',
       }

   def transition_save(self):
       pool = Pool()
       Incidence = pool.get('incidents')
       incidence = Incidence.browse(Transaction().context['active_ids'])
       incidence.closing_date = self.parameters.closing_date
       incidence.solution_summary = self.parameters.solution_summary
       incidence.state = self.parameters.state
       incidence.sub_state = self.parameters.sub_state
       incidence.save()
       return 'end'

:roll_eyes: Are we missing something?

The browse method returns a list, so you may have more success with something like:

def transition_save(self):
    pool = Pool()
    Incident = pool.get('incidents')
    incidents = Incident.browse(Transaction().context['active_ids'])
    for incident in incidents:
        incident.closing_date = self.parameters.closing_date
        incident.solution_summary = self.parameters.solution_summary
        incident.state = self.parameters.state
        incident.sub_state = self.parameters.sub_state
    Incident.save(incidents)
    return 'end'

Hello @dave,
your help put the icing on the cake !

Our code now works perfectly.

@ced, @dave thank you.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.