来自:http://shine-it.net/index.php/topic,16142.0.html
在openerp展示界面通常是通过定义class的view(xml文件)来实现的。
有时这种方法不能支持用户自定义字段的需求,于是就可以通过重写fields_view_get()、 read()来实现。
实例代码
# -*- coding: utf-8 -*- from openerp.osv import osv,fields from lxml import etree from openerp import tools from openerp.tools import to_xml class AnalysisQuestionnaireType(osv.osv): _name = 'analysis.questionnaire.type' _description = '问卷类型' _columns = { 'name': fields.char('名称', size=125, required=True), 'analysis_set': fields.many2many('analysis.title.set', id1='analysis_questionnaire_type_id', id2='analysis_title_set_id', string='主题'), } class AnalysisTitleSet(osv.osv): _name = "analysis.title.set" _description = "主题" _columns = { "name": fields.char(string="名称", size=125, required=True,), 'analysis_questionnaire_type': fields.many2many('analysis.questionnaire.type', id1='analysis_title_set_id', id2='analysis_questionnaire_type_id', string='问卷类型'), "analysis_title": fields.one2many('analysis.title', 'set', '题目'), } class AnalysisTitle(osv.osv): _name = "analysis.title" _description = "题目" _columns = { "name": fields.char(string="名称", size=125, required=True), "note": fields.text("描述"), "set": fields.many2one("analysis.title.set", string="主题", required=True), 'type': fields.selection([('multiple_choice_only_one_ans', '单项选择'), ('multiple_choice_multiple_ans', '多项选择'), ('matrix_of_choices_only_one_ans', '单选组合'), ('single_textbox', '单行文本框'), ('multiple_textbox', '多个单行文本框'), ('comment', '多行文本框'), ('date', '日期框'), ('date_and_time', '日期时间框'), ('descriptive_text', '描述性文本'), ('attachment', '附件'), ('image', '图片'), ], '题目类型', required=1,), 'is_require_answer': fields.boolean('必填项'), 'option_id': fields.one2many('analysis.title.option', 'title_id', '备选答案'), 'column_heading_ids': fields.one2many('analysis.title.column.heading', 'title_id', '标题'), 'descriptive_text': fields.text('描述文本'), } class AnalysisTitleOption(osv.osv): _name = 'analysis.title.option' _description = '答案选项' _columns = { 'title_id': fields.many2one('analysis.title', '题目', ondelete='cascade'), 'option': fields.char('答案选项', size=128, required=True), 'type': fields.selection([('char', '字符型'), ('date', '日期'), ('datetime', '日期时间型'), ('integer', '整数型'), ('float', '小数型'), ('selection', '选择型')], '答案类型', required=True), } class AnalysisTitleColumnHeading(osv.osv): _name = 'analysis.title.column.heading' _description = '选项标题' _columns = { 'name': fields.char('选项标题', size=128, required=True), 'title_id': fields.many2one('analysis.title', '题目', ondelete='cascade'), } class AnalysisAnswer(osv.osv): _name = 'analysis.answer' _description = '答案' _columns = { 'analysis_questionnaire': fields.many2one('analysis.questionnaire', '问卷'), 'value': fields.text('值') } class AnalysisQuestionnaire(osv.osv): _name = 'analysis.questionnaire' _description = '分析问卷' _columns = { "name": fields.char(string='名称', size=125, required=True), 'type': fields.many2one('analysis.questionnaire.type', string='类型', required=True), 'title': fields.one2many('analysis.answer', "analysis_questionnaire", "答案"), } def default_get(self, cr, uid, fields_list, context=None): default = super(AnalysisQuestionnaire, self).default_get(cr, uid, fields_list, context=context) con = context.get('type') default['type'] = con return default def view_init(self, cr, uid, fields_list, context=None): pass def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False,): if context is None: context = {} result = super(AnalysisQuestionnaire, self).fields_view_get(cr, uid, view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) if view_type == 'form' and context.has_key('type'): view = etree.fromstring(result['arch']) fields = result['fields'] print etree.tostring(view) notebook = etree.SubElement(view, 'notebook') sets = self.pool.get('analysis.questionnaire.type').browse(cr, uid, context['type']).analysis_set q_no = 0 for set in sets: page = etree.SubElement(notebook, 'page', string=set.name) for title in set.analysis_title: q_no += 1 etree.SubElement(page, 'newline') if title.is_require_answer: etree.SubElement(page, 'separator', {'string': '*'+tools.ustr(q_no)+'.'+tools.ustr(title.name)}) else: etree.SubElement(page, 'separator', {'string': tools.ustr(q_no)+'.'+tools.ustr(title.name)}) if title.type == 'multiple_choice_only_one_ans': parent = etree.SubElement(page, 'group') selection = [] for option in title.option_id: selection.append((tools.ustr(option.id), option.option)) fields['title'+'_'+tools.ustr(title.id)+'_selection'] = {'type': 'selection', 'selection': selection, 'name': title.name} etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'_selection'}) elif title.type == 'multiple_choice_multiple_ans': parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'}) for option in title.option_id: etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'option'+'_' + tools.ustr(option.id)}) fields['title'+'_'+tools.ustr(title.id)+'-'+'option'+'_' + tools.ustr(option.id)] = {'type': 'boolean', 'string': option.option} elif title.type == 'matrix_of_choices_only_one_ans': parent = etree.SubElement(page, 'group', {'col': '2', 'colspan': '2'}) selection = [] for option in title.option_id: selection.append((tools.ustr(option.id), option.option)) for col in title.column_heading_ids: etree.SubElement(parent, 'newline') etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_' + tools.ustr(col.id), }) fields['title'+'_'+tools.ustr(title.id)+'-'+'col'+'_' + tools.ustr(col.id)] = {'type': 'selection', 'selection': selection} elif title.type == 'single_textbox': parent = etree.SubElement(page, 'group',) etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id) + "_single", 'nolabel': "1", 'colspan': "4"}) fields['title'+'_'+tools.ustr(title.id) + "_single"] = {'type': 'char', 'size': 255} elif title.type == 'multiple_textbox': parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'}) for col in title.column_heading_ids: fields['title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'+tools.ustr(col.id)] = {'type': 'char', 'size': 255} etree.SubElement(parent, 'field', {'width': '300', 'colspan': '1', 'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_' + tools.ustr(col.id)}) elif title.type == 'comment': parent = etree.SubElement(page, 'group') etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id) + "_comment", 'nolabel': "1", 'colspan': "4"}) fields['title'+'_'+tools.ustr(title.id) + "_comment"] = {'type': 'text'} elif title.type == 'date': parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'}) for col in title.column_heading_ids: fields['title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'+tools.ustr(col.id)] = {'type': 'date'} etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_' + tools.ustr(col.id)}) elif title.type == 'date_and_time': parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'}) for col in title.column_heading_ids: fields['title'+'_'+tools.ustr(title.id)+'-' + 'col'+'_'+tools.ustr(col.id)] = {'type': 'datetime'} etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_' + tools.ustr(col.id)}) elif title.type == 'attachment': parent = etree.SubElement(page, 'group',) fields['title'+'_'+tools.ustr(title.id)+'_attachment'] = {'type': 'binary'} etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'_attachment'}) elif title.type == 'descriptive_text': parent = etree.SubElement(page, 'group') if title.descriptive_text: for que_test in title.descriptive_text.split('\n'): etree.SubElement(parent, 'label', {'string': to_xml(tools.ustr(que_test)), 'align': "0.0"}) elif title.type == 'image': parent = etree.SubElement(page, 'group',) fields['title'+'_'+tools.ustr(title.id)+'_image'] = {'type': 'binary'} etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'_image', 'widget': 'image'}) result['arch'] = etree.tostring(view) return result def create(self, cr, uid, vals, context=None): answer_obj = self.pool.get("analysis.answer") questionnaire_vals = {'name': vals.get('name'), 'type': vals.get('type')} vals.pop('name', "not name") vals.pop('type', 'not type') answer_vals = {} questionnaire_id = super(AnalysisQuestionnaire, self).create(cr, uid, questionnaire_vals, context=context) answer_vals['analysis_questionnaire'] = questionnaire_id answer_vals['value'] = vals answer_obj.create(cr, uid, answer_vals, context=context) return questionnaire_id def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): result = super(AnalysisQuestionnaire, self).read(cr, user, ids, fields=fields, context=context, load=load) answer_obj = self.pool.get('analysis.answer') i = 0 while i < len(result): answer_list = answer_obj.search(cr, user, [('analysis_questionnaire', '=', result['id'])]) if answer_list: val = eval(answer_obj.read(cr, user, answer_list, ['value'], context=context)[0]['value']) result.update(val) i += 1 return result
上述代码用户可以自己定义问卷题目及题目类型。通过fields_view_get()画出view,然后把动态构建的字段及其值通过重写create() 把数据存储到另外一个表里。这里用的是一个text字段把create返回的值直接存储起来的。当需要查看保存过的数据时,通过重写read()整理成需要的数据格式返回。