[REF] developer: rewrite sql view as a howto

SQL view was formerly part of the dashboard tutorial which is now
obsolete. Since creating a SQL view as a tutorial does not make sense
anymore, it has been converted into a simple howto.

closes odoo/documentation#4031

Task: 3226581
Signed-off-by: Tiffany Chang <tic@odoo.com>
This commit is contained in:
Tiffany Chang (tic) 2023-04-04 14:50:43 +00:00 committed by Antoine Vandevenne (anv)
parent e2c880aafe
commit 7124542ed9
2 changed files with 125 additions and 0 deletions

View File

@ -14,6 +14,7 @@ How-to guides
howtos/javascript_client_action
howtos/web_services
howtos/company
howtos/create_reports
howtos/accounting_localization
howtos/translations
howtos/provide_iap_services
@ -52,6 +53,11 @@ How-to guides
Learn how to manage multiple companies and deal with the records-related specificities of a
multi-company environment.
.. card:: Create customized reports
:target: howtos/create_reports
Learn how to create customized reports with SQL Views.
.. card:: Accounting localization
:target: howtos/accounting_localization

View File

@ -0,0 +1,119 @@
=========================
Create customized reports
=========================
SQL views are a technique for creating customized reports to show data that cannot be
shown with existing models' fields and views. In other words, this technique helps avoid
unnecessary creation and calculation of additional fields solely for data analysis
purposes.
Create a model
==============
A SQL view is created in a similar manner as a standard model:
.. code-block:: python
from odoo import fields, models
class ModuleReport(models.Model):
_name = 'module.report'
_description = "Module Report"
_rec_name = 'module_field'
_auto = False
Where the attributes:
- `_auto = False` indicates that we do not want to store the model in the database
- `_rec_name` indicates which of the model's fields represents a record's name (i.e. the
name that will be used in the navigation breadcrumb when opening a record's form view)
and its fields are defined in the same way as a standard model, except every field is
marked as `readonly=True`.
.. note::
Don't forget to add your new model to your security file.
Populate the model
==================
There are 2 ways to populate a SQL view's table:
- override the `BaseModel.init()` method,
- set the `_table_query` property.
Regardless of which way is used, a SQL query will be executed to populate the model.
Therefore, any SQL commands can be used to collect and/or calculate the data needed
and you are expected to keep in mind that you are bypassing the ORM (i.e. it is a
good idea to read through :ref:`reference/security` if you haven't already). The columns
returned from the `SELECT` will populate the model's fields, so ensure that your column
names match your field names, or use alias names that match.
.. tabs::
.. tab:: Overriding `BaseModel.init()`
In most cases, overriding the `BaseModel.init()` method is the standard and better option to
use. It requires the import of `tools` and is typically written as follows:
.. code-block:: python
def init(self):
tools.drop_view_if_exists(self.env.cr, self._table)
self.env.cr.execute("""CREATE or REPLACE VIEW %s as (
SELECT
%s
FROM
%s
)""" % (self._table, self._select(), self._from()))
`tools.drop_view_if_exists` ensures that a conflicting view is not created when the
SQL query is executed. It is standard to separate the different parts of the query to
allow for easier model extension. Exactly how the query is split up across methods is not
standardized, but at minimum, the `_select` and `_from` methods are common, and of course,
all these methods will return strings.
.. seealso::
`Example: a SQL view using an override of BaseModel.init()
<{GITHUB_PATH}/addons/project/report/project_report.py>`_
.. tab:: Using `_table_query`
The ``_table_query`` property is used when the view depends on the context. It is typically
written as follows:
.. code-block:: python
@property
def _table_query(self):
return 'SELECT %s FROM %s' % (self._select(), self._from())
and follows the same `_select` and `_from` methods standards as `BaseModel.init()`.
An example of when the property should be used instead of overriding `BaseModel.init()`
is in a multi-company and multi-currency environment where currency related amounts need
to be converted using currency exchange rates when the user switches between companies.
.. seealso::
`Example: a SQL view using _table_query
<{GITHUB_PATH}/addons/account/report/account_invoice_report.py>`_
Use the model
=============
Views and menu items for your SQL views are created and used in the same way as any
other Odoo model. You are all set to start using your SQL view. Have fun!
Extra tips
==========
.. tip::
A common mistake in SQL views is not considering the duplication of certain data
due to table JOINs. This can lead to miscounting when using a field's `group_operator`
and/or the pivot view. It is best to test your SQL view with sufficient data to ensure the
resulting field values are as you expect.
.. tip::
If you have a field that you do not want as a measure (i.e., in your pivot or graph views), add
`store=False` to it, and it will not show.