Odoo 开发前台页面和模板引擎的使用

方式一:使用Qweb

带站点基础框的页面

后台代码

  1. @http.route('/trial', auth='public', type='http', website=True)
  2. def trial(self, **kw):
  3. # ...
  4. values = {
  5. 'plan': trial_plan,
  6. }
  7. return request.render('saas_portal.try_trial', values)

模板

  1. <template id="try_trial">
  2. <t t-call="website.layout">
  3. <t t-set="title">Try trial</t>
  4. <div class="oe_structure">
  5. <div class="container" style="text-align: center">
  6. <h2>开通: <t t-esc="plan.name"/></h2>
  7. <p>实例正在创建中...</p>
  8. <p>这可能需要几分钟,请稍后在 <a href="/my/home">我的账号</a> 页面 SaaS 栏查看创建的结果</p>
  9. </div>
  10. </div>
  11. </t>
  12. <script>
  13. $(document).ready(function() {
  14. $('div.oe_structure div.container').css('height', $(window).innerHeight());
  15. });
  16. </script>
  17. </template>
  • 可以看到模板首先使用了website.layout 这样页面内容就放置在一个公共的站点基础框内
  • Qweb模板引擎使用xml写法,标签大多以 t 开头
  • Qweb模板定义的xml文件要加入到模块定义文件的data组下,随模块安装后保存到数据库的视图表ir_ui_view,渲染页面时从数据库读取

完全自定义的页面

后台代码

  1. @http.route('/payment/order_status_show', type='http', auth='public', website=True, methods=['GET'], csrf=False)
  2. def order_status_show(self, **params):
  3. # ...
  4. values = {
  5. 'transaction': tx,
  6. 'order': order[0].id
  7. }
  8. return request.render("payment.order_status_show", values)

模板

  1. <template id="order_status_show" name="orderstatus" page="True">
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  5. <meta charset="utf-8"/>
  6. <meta http-equiv="pragma" content="no-cache"/>
  7. <meta http-equiv="cache-control" content="no-cache"/>
  8. <meta http-equiv="expires" content="0"/>
  9. <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"/>
  10. <title>
  11. 订单确认
  12. </title>
  13. <link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
  14. <link rel="stylesheet" type="text/css" href="/payment_weixin/static/src/css/qrcode_pay.css"/>
  15. </head>
  16. <body>
  17. <!-- p-header -->
  18. <div class="p-header">
  19. <div class="w">
  20. <div id="logo">
  21. <a href="/"><img width="120" height="40" src="/logo.png" alt="Logo" title="点击返回首页"/></a>
  22. 订单确认
  23. </div>
  24. </div>
  25. </div>
  26. <!-- p-header end -->
  27. <div class="main">
  28. <div class="w">
  29. <!-- order 订单信息 -->
  30. <!-- order 订单信息 -->
  31. <div class="order">
  32. <div class="o-left">
  33. <h3 class="o-title">
  34. <t t-esc="'恭喜,您的订单创建成功! 订单号:'+ transaction.reference" />
  35. </h3>
  36. <p class="o-tips">
  37. 谢谢光顾,期盼您的
  38. <span class="font-red">
  39. 下次
  40. </span>
  41. 光临。<a t-attf-href="/my/orders/{{ order }}">查看</a> 订单详细
  42. </p>
  43. </div>
  44. <div class="o-right">
  45. <t t-if="transaction.state == 'done'">
  46. <div class="o-price">
  47. <em>
  48. 已付金额
  49. </em>
  50. <strong>
  51. <t t-esc="transaction.amount" />
  52. </strong>
  53. <em>
  54. </em>
  55. </div>
  56. </t>
  57. </div>
  58. <div class="clr">
  59. </div>
  60. </div>
  61. <!-- order 订单信息 end -->
  62. <!-- order 订单信息 end -->
  63. <!-- payment 支付方式选择 -->
  64. <div class="payment">
  65. <!-- 微信支付 -->
  66. <div class="pay-weixin">
  67. <div class="p-w-hd">
  68. 微信关注我们
  69. </div>
  70. <div class="p-w-bd" style="position:relative">
  71. <div class="p-w-box">
  72. <div class="pw-box-hd">
  73. <img src="http://mall.ziranyidu.com/wx.png" width="298"/>
  74. </div>
  75. <div class="pw-box-ft">
  76. <p>
  77. 请使用微信扫一扫
  78. </p>
  79. <p>
  80. 扫描二维码关注我们
  81. </p>
  82. </div>
  83. </div>
  84. <div class="p-w-sidebar">
  85. </div>
  86. </div>
  87. </div>
  88. <!-- 微信支付 end -->
  89. </div>
  90. <!-- payment 支付方式选择 end -->
  91. </div>
  92. </div>
  93. </body>
  94. </html>
  95. </template>

方式二:使用Jinja2

以odoo数据库创建页面为例

后台代码

  1. import jinja2
  2. loader = jinja2.PackageLoader('odoo.addons.web', "views")
  3. env = jinja2.Environment(loader=loader, autoescape=True)
  4. class Database(http.Controller):
  5. def _render_template(self, **d):
  6. d.setdefault('manage',True)
  7. d['insecure'] = odoo.tools.config['admin_passwd'] == 'admin'
  8. d['list_db'] = odoo.tools.config['list_db']
  9. d['langs'] = odoo.service.db.exp_list_lang()
  10. d['countries'] = odoo.service.db.exp_list_countries()
  11. # databases list
  12. d['databases'] = []
  13. try:
  14. d['databases'] = http.db_list()
  15. except odoo.exceptions.AccessDenied:
  16. monodb = db_monodb()
  17. if monodb:
  18. d['databases'] = [monodb]
  19. return env.get_template("database_manager.html").render(d)
  20. @http.route('/web/database/manager', type='http', auth="none")
  21. def manager(self, **kw):
  22. return self._render_template(

关键代码return env.get_template("database_manager.html").render(d) 注意这里的 env 和 request.env 没什么关系,不能搞混了

上面的jinja2.PackageLoader('odoo.addons.web', "views")设置模块引擎从 web 模块的 views 目录下寻找模板文件

模板(节选部分)

  1. <div class="form-group">
  2. <div class="row">
  3. <div class="col-md-12">
  4. <label for="name" class="control-label">Database Name</label>
  5. <input id="name" type="text" name="name" class="form-control" required="required" autocomplete="off"/>
  6. </div>
  7. </div>
  8. </div>
  9. <div class="form-group">
  10. <div class="row">
  11. <div class="col-md-12">
  12. <label for="login" class="control-label">Email</label>
  13. <input id="login" type="text" name="login" class="form-control" required="required" autocomplete="off"/>
  14. </div>
  15. </div>
  16. </div>
  17. <div class="form-group has-feedback">
  18. <label for="password" class="control-label">Password</label>
  19. <input id="password" type="password" name="password" class="form-control" required="required" autocomplete="off"/>
  20. <span class="fa fa-eye o_little_eye form-control-feedback" aria-hidden="true" style="cursor: pointer; pointer-events: auto"></span>
  21. </div>
  22. <div class="form-group">
  23. <div class="row">
  24. <div class="col-md-6">
  25. <label for="lang" class="control-label">Language</label>
  26. <select id="lang" name="lang" class="form-control" required="required" autocomplete="off">
  27. {% for lang in langs %}
  28. <option {% if lang[0] == "zh_CN" %}selected="selected" {% endif %}value="{{ lang[0] }}">{{ lang[1] }}</option>
  29. {% endfor %}
  30. </select>
  31. </div>
  32. <div class="col-md-6">
  33. <label for="country" class="control-label">Country</label>
  34. <select id="country" name="country_code" class="form-control" autocomplete="off">
  35. <option value=""></option>
  36. {% for country in countries %}
  37. <option {% if country[0] == "cn" %}selected="selected" {% endif %}value="{{ country[0] }}">{{ country[1] }}</option>
  38. {% endfor %}
  39. </select>
  40. </div>
  41. </div>
  42. </div>
  43. <div class="form-group">
  44. <div class="checkbox">
  45. <label>
  46. <input name="demo" type="checkbox" class="pull-right" value="1">
  47. <span>Load demonstration data</span>
  48. <span class="text-muted"> (Check this box to evaluate Odoo)</span>
  49. </label>
  50. </div>
  51. </div>

使用Jinja2引擎的模板文件直接在文件系统里,渲染页面时不需要读数据库,相对快一些,但管理不如Qweb可以直接在线编辑那样方便


Related