如何在 Python 中使用多级字典创建 Odoo 记录

Posted

技术标签:

【中文标题】如何在 Python 中使用多级字典创建 Odoo 记录【英文标题】:How to create Odoo records with multilevel dictionaries in Python 【发布时间】:2021-12-22 11:47:25 【问题描述】:

我正在努力创建一种递归方法来自动在 Odoo 中创建记录。 我请求 SOAP 服务的 WSDL 并对其进行处理,直到收到以下字符串:

'notificaCertificadoRevocado':
   'input': 
      'SolicitudNotificaRevocado':
         'optional': False,
         'type': 
            'certificado': 
                'optional': False,
                'type': 'String(value)'
                ,
            'codigoAmbiente': 
                'optional': False,
                'type': 'Int(value)'
                
             
          
       
   

这本词典有 1 个父参数“SolicitudNotificaRevocado”和 2 个子参数“certificado”和“codigoAmbiente”。

目前我的 python 方法如下所示:

    def _prepare_parameter_list(self, parameter_dict, recursive_data=False):
        building_data = recursive_data if recursive_data else 
        parameter_list = []
        for key, value in parameter_dict.items():
            if key != 'optional' and key != 'type':
                # Create parameters
                parameter_name_dict = 
                    'name': key,
                    'description': ' '.join(word.capitalize() for word in camel_case_split(key)),
                
                characterization_dict = self._prepare_parameter_list(value)
                built_parameter_dict = **parameter_name_dict, **characterization_dict
                parameter_list.append((0, 0, built_parameter_dict))
                # TODO: Here the code stops
                return parameter_list
            else:
                if key == 'optional':
                    building_data = **building_data, **'optional': value
                if key == 'type':
                    if isinstance(value, dict):
                        building_data = **building_data, **'parameter_ids': self._prepare_parameter_list(value)
                    else:
                        building_data = **building_data, **'type': value.split('(')[0]
        return building_data

这很好用,只有一个问题,返回的数据具有以下形式:

[(0, 0, 
   'name': 'SolicitudOperacionesCuis',
   'description': 'Solicitud Operaciones Cuis',
   'optional': False,
   'parameter_ids': [
      (0, 0, 
         'name': 'codigoAmbiente',
         'description': 'Codigo Ambiente',
         'optional': False,
         'type': 'Int')]
      )
      ]

问题是处理其中一个子参数后的方法由于“返回参数列表”部分而停止。 (我什至在问题部分添加了 TODO 注释) 我想检索以下数据:

[(0, 0, 
   'name': 'SolicitudOperacionesCuis',
   'description': 'Solicitud Operaciones Cuis',
   'optional': False,
   'parameter_ids': [
      (0, 0, 
         'name': 'certificado',
         'description': 'Certificado',
         'optional': False,
         'type': 'String')]
      ),
      (0, 0, 
         'name': 'codigoAmbiente',
         'description': 'Codigo Ambiente',
         'optional': False,
         'type': 'Int')]
      )
       ]

我应该如何调整我的方法来实现这一点? 使用递归方法很难!

【问题讨论】:

在您的预期输出中,parameter_ids 是否应该是两次相同数据的列表。还是输入数据有更多选项可供选择? 对不起,我犯了一个错误,我用预期的输出纠正了 从您在递归调用发生的characterization_dict = self._prepare_parameter_list(value) 中的命名来看,您似乎在期待一本字典,但在 TODO 之后您的 return 正在返回一个列表。应该这样吗? 我知道,这篇文章是关于调整我方法的那一部分。不让这个工作的部分。 【参考方案1】:

如果输入数据是已知的,并且有用的数据似乎是输入字典中的数据,那么您不需要递归元素。 更新了下面的类似函数,输出您的预期输出

def _prepare_parameter_list(parameter_dict):
    def _return_data_type(value_type):
        if value_type == 'Int':
            value_type = 'int'
        elif value_type == 'String':
            value_type = 'str'
        elif value_type == 'Long':
            value_type = 'float'
        return value_type

    parent = parameter_dict.get('notificaCertificadoRevocado')
    building_data = []
    if parent and parent.get('input'):
        for key, value in parent['input']:
            vals = 
                'name': key,
                'description': ' '.join(word.capitalize() for word in camel_case_split(key)),
                'optional': value.get('optional'),
            
            parameter_ids = []
            if value.get('type'):
                for par_key, par_value in value['type']:
                    pams = 
                        'name': par_key,
                        'description': par_key.capitalize(),
                        'optional': par_value.get('optional'),
                        'type': par_value.get('type') and _return_data_type(par_value['type'].split('(')[0]) or False,
                    
                    parameter_ids.append((0, 0, pams))
            vals.update(parameter_ids=parameter_ids)
            building_data.append((0, 0, vals))
    return building_data

【讨论】:

问题是数据是未知的,所以获取 'notificaCertificadoRevocado' 是一种非常有限的方法。【参考方案2】:

最后,我采用了不同的方法彻底重构了该方法。 因为我之前的代码还有一个问题。如果检查上一个所需的输出:

[(0, 0, 
   'name': 'SolicitudOperacionesCuis',
   'description': 'Solicitud Operaciones Cuis',
   'optional': False,
   'parameter_ids': [
      (0, 0, 
         'name': 'certificado',
         'description': 'Certificado',
         'optional': False,
         'type': 'String')]
      ),
      (0, 0, 
         'name': 'codigoAmbiente',
         'description': 'Codigo Ambiente',
         'optional': False,
         'type': 'Int')]
      )
       ]

有一个 Odoo 无法识别的嵌套 One2many 记录创建。 无论如何,由于我无法使之前的代码工作,我开始单独创建记录:

    def _create_parameters(self, process_object, parameter_id=False, parent_parameter_id=False):
        for key, value in process_object.items():
            if key != 'optional' and key != 'type':
                try:
                    soap_parameter = self.env['soap.parameter'].search([
                        '&', '&', '&', '&',
                        ['active', '=', True],
                        ['name', '=', key],
                        ['description', '=', ' '.join(word.capitalize() for word in camel_case_split(key))],
                        ['method_id', '=', self.id],
                        ['parent_id', '=', parent_parameter_id]
                    ], limit=1)[0]
                except IndexError:
                    # Create parameters
                    soap_parameter = self.env['soap.parameter'].create(
                        'name': key,
                        'description': ' '.join(word.capitalize() for word in camel_case_split(key)),
                        'method_id': self.id,
                        'parent_id': parent_parameter_id
                    )
                self._create_parameters(value, soap_parameter, soap_parameter.id)
            if parameter_id:
                if key == 'optional':
                    parameter_id.write('optional': value)
                if key == 'type':
                    if isinstance(value, dict):
                        self._create_parameters(value, parent_parameter_id=parent_parameter_id)
                    else:
                        value_type = value.split('(')[0]
                        if value_type == 'Int':
                            value_type = 'int'
                        elif value_type == 'String':
                            value_type = 'str'
                        elif value_type == 'Long':
                            value_type = 'float'
                        parameter_id.write('type': value_type)

此代码将搜索并更新或创建我的参数。

【讨论】:

以上是关于如何在 Python 中使用多级字典创建 Odoo 记录的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Odoo 12 中使用 Python XML-RPC 注册付款

python3之利用字典和列表实现城市多级菜单

初识python: 字典

如何正确更改 odoo 12 视图显示?

如何在 Python 中遍历 N 级嵌套字典?

python list 嵌套 dict 按照字典中的单个key进行单级排序 或 按照多个键进行多级排序