[Wizard] Create Many2One domain on One2Many in the same form

I have a wizard with a One2Many field. A user adds data to that field. After that the user have to do one step more and should select one item from the list created with the One2Many. How is this possible?

The code:

documents = fields.One2Many(‘document.document’, ‘resources’, ‘Additional Documents’)
calibration_cert = fields.Many2One(‘document.document’, ‘Calibration certificate’,
(‘type’, ‘=’, ‘calibration_cert’),
(‘id’, ‘in’, Eval(‘documents’, )),
help=“Select a document as calibration certificate.”)

I can add the documents, but the selection of the field calibration_cert stays empty.

Of course, the record created in the One2Many do not exist in the database so the search on the Many2One can not find them. Your pre-selection of record should be based on already saved record (e.g. with a Many2Many). Or you must use something else to find the specific record (e.g. you take the first one).

Would it be possible to create a selection field and fill that dynamically with the list of documents from the One2Many? I created a second form, so the user first adds the documents and clicks on “next”. After that in the second form the user gets the possibility to select the right document.

If you do not store the records of One2Many, I do not see how you could make reference to them as they will not have a unique id.

I guess you can’t without a hack.

I think that the most you can do is add a label that tells the user that she must save before they can use newly created records of the O2M. Or as Cédric suggests, use the order of the records. That is not a possibility, however when the value must depend on company, for example.

What we do in the only case we need something like that is to teach the user they must save before picking the records in the m2o field.

I had a similar situation then I added a boolean field to document.document (calibration_cert) and I validated that the resource has one, and only one, document type calibration_cert:

class Document(ModelSQL,ModelView):
	"""Document Model """
	__name__ = 'document.document'
	calibration_cert = fields.Boolean('Calibration Cert')

class YourModel(ModelSQL,ModelView):
	"""Your Model"""

	documents = fields.One2Many(‘document.document’, ‘resources’, ‘Additional Documents’)
	calibration_cert = fields.Function(Fields.Many2One(),'get_calibration_cert')

	def get_calibration_cert(self):
		if self.documents:
			for document in self.documents:
				if document.calibration_cert:
					return document.id
		return None

	def pre_validate(self):
		calibration_certs = 0
		for document in self.documents:
			if document.calibration_cert:
				calibration_certs += 1
		if calibration_certs != 1:
			self.raise_user_error("Error Only one document type calibration cert")

Such validation is OK for ModelView only. If it is stored in the database, you must use a UNIQUE SQL constraint to work with concurrency.

but I had problems with Unique constraint when a resource have more than 2 documents:

Unique(cls.table(), table.document,table.calibration_cert)

  • Document: 1, resource: 1, calibration_cert = False
  • Document: 2, resource: 1, calibration_cert = True
  • Document: 3, resource: 1, calibration_cert = False
    Unique constraint fail

but the validation can be put on ModelStorage.validate or write method.

Yes you are right. It is not Unique but Exclude that should be used for partial constraint.

1 Like

Just to mention, it’s a Wizard and indeed it’s not possible (yet?) to set a domain based on a other field in the wizard.

I have tried to get the filename in a Selection, so the user can select the name, but that also didn’t work. Added a “next” transition also no luck.

I ended up by letting the user fill in as much as possible in the Wizard and then the last action is a StateAction, which opens the completed calibration, so the user can kind of fine tune the data and then close it.

1 Like

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