[REM] developer: remove references to web_dashboard view

Since odoo/enterprise#31641 the dashboard view no longer exists since it
is now replaced with spreadsheet_dashboard, therefore we remove it from
the backend Views documentation.

Task: 3226581
X-original-commit: e2c880aafe
Part-of: odoo/documentation#4034
This commit is contained in:
Tiffany Chang (tic) 2023-03-23 15:50:04 +00:00
parent 0440f5c5cd
commit b742c44f09
7 changed files with 1 additions and 590 deletions

View File

@ -124,7 +124,7 @@ an impact on all view types.
``info``, ``warning``, ``danger`` and ``secondary`` displays. The list view supports ``bf``,
``it``, ``success``, ``info``, ``warning``, ``danger``, ``muted`` and ``primary`` displays.
* ``sample`` (``kanban`` & ``list`` & ``gantt`` & ``graph`` & ``pivot`` & ``cohort`` & ``dashboard``)
* ``sample`` (``kanban`` & ``list`` & ``gantt`` & ``graph`` & ``pivot`` & ``cohort``)
Populate the view with a set of sample records if none are found for the current model.
This attribute is false by default.
@ -577,213 +577,6 @@ attributes:
measures (useful for fields that do not make sense aggregated, such as fields in different
units, e.g. € and $).
.. _reference/views/dashboard:
Dashboard
---------
.. raw:: html
<span class="badge" style="background-color:#AD5E99">Enterprise feature</span>
Like pivot and graph view, The dashboard view is used to display aggregate data.
However, the dashboard can embed sub views, which makes it possible to have a
more complete and interesting look on a given dataset.
The dashboard view can display sub views, aggregates for some fields (over a
domain), or even *formulas* (expressions which involves one or more aggregates).
For example, here is a very simple dashboard:
.. code-block:: xml
<dashboard>
<view type="graph" ref="sale_report.view_order_product_graph"/>
<group string="Sale">
<aggregate name="price_total" field="price_total" widget="monetary"/>
<aggregate name="order_id" field="order_id" string="Orders"/>
<formula name="price_average" string="Price Average"
value="record.price_total / record.order_id" widget="percentage"/>
</group>
<view type="pivot" ref="sale_report.view_order_product_pivot"/>
</dashboard>
The root element of the Dashboard view is <dashboard>, it does not accept any
attributes.
There are 5 possible type of tags in a dashboard view:
.. rst-class:: o-definition-list
``view``
declares a sub view.
Admissible attributes are:
.. rst-class:: o-definition-list
``type`` (mandatory)
The type of the sub view. For example, *graph* or *pivot*.
``ref`` (optional)
An xml id for a view. If not given, the default view for the model will
be used.
``name`` (optional)
A string which identifies this element. It is mostly
useful to be used as a target for an xpath.
``group``
defines a column layout. This is actually very similar to the group element
in a form view.
Admissible attributes are:
.. rst-class:: o-definition-list
``string`` (optional)
A description which will be displayed as a group title.
``colspan`` (optional)
The number of subcolumns in this group tag. By default, 6.
``col`` (optional)
The number of columns spanned by this group tag (only makes sense inside
another group). By default, 6.
``aggregate``
declares an aggregate. This is the value of an aggregate for a given field
over the current domain.
Note that aggregates are supposed to be used inside a group tag (otherwise
the style will not be properly applied).
Admissible attributes are:
.. rst-class:: o-definition-list
``field`` (mandatory)
The field name to use for computing the aggregate. Possible field types
are:
- ``integer`` (default group operator is sum)
- ``float`` (default group operator is sum)
- ``many2one`` (default group operator is count distinct)
``name`` (mandatory)
A string to identify this aggregate (useful for formulas)
``string`` (optional)
A short description that will be displayed above the value. If not
given, it will fall back to the field string.
``domain`` (optional)
An additional restriction on the set of records that we want to aggregate.
This domain will be combined with the current domain.
``domain_label`` (optional)
When the user clicks on an aggregate with a domain, it will be added to
the search view as a facet. The string displayed for this facet can
be customized with this attribute.
``group_operator`` (optional)
A valid postgreSQL aggregate function identifier to use when aggregating
values (see https://www.postgresql.org/docs/12/static/functions-aggregate.html).
If not provided, By default, the group_operator from the field definition is used.
Note that no aggregation of field values is achieved if the group_operator value is "".
.. note:: The special aggregate function ``count_distinct`` (defined in odoo) can also be used here
.. code-block:: xml
<aggregate name="price_total_max" field="price_total" group_operator="max"/>
``col`` (optional)
The number of columns spanned by this tag (only makes sense inside a
group). By default, 1.
``widget`` (optional)
A widget to format the value (like the widget attribute for fields).
For example, monetary.
``help`` (optional)
A help message to dipslay in a tooltip (equivalent of help for a field in python)
``measure`` (optional)
This attribute is the name of a field describing the measure that has to be used
in the graph and pivot views when clicking on the aggregate.
The special value __count__ can be used to use the count measure.
.. code-block:: xml
<aggregate name="total_ojects" string="Total Objects" field="id" group_operator="count" measure="__count__"/>
``clickable`` (optional)
A boolean indicating if this aggregate should be clickable or not (default to true).
Clicking on a clickable aggregate will change the measures used by the subviews
and add the value of the domain attribute (if any) to the search view.
``value_label`` (optional)
A string put on the right of the aggregate value.
For example, it can be useful to indicate the unit of measure
of the aggregate value.
``formula``
declares a derived value. Formulas are values computed from aggregates.
Note that like aggregates, formulas are supposed to be used inside a group
tag (otherwise the style will not be properly applied).
Admissible attributes are:
.. rst-class:: o-definition-list
``value`` (mandatory)
A string expression that will be evaluated, with the builtin python
evaluator (in the web client). Every aggregate can be used in the
context, in the ``record`` variable. For example,
``record.price_total / record.order_id``.
``name`` (optional)
A string to identify this formula
``string`` (optional)
A short description that will be displayed above the formula.
``col`` (optional)
The number of columns spanned by this tag (only makes sense inside a
group). By default, 1.
``widget`` (optional)
A widget to format the value (like the widget attribute for fields).
For example, monetary. By default, it is 'float'.
``help`` (optional)
A help message to dipslay in a tooltip (equivalent of help for a field in python)
``value_label`` (optional)
A string put on the right of the formula value.
For example, it can be useful to indicate the unit of measure
of the formula value.
``widget``
Declares a specialized widget to be used to display the information. This is
a mechanism similar to the widgets in the form view.
Admissible attributes are:
.. rst-class:: o-definition-list
``name`` (mandatory)
A string to identify which widget should be instantiated. The view will
look into the ``widget_registry`` to get the proper class.
``col`` (optional)
The number of columns spanned by this tag (only makes sense inside a
group). By default, 1.
.. _reference/views/form:
Form

View File

@ -15,7 +15,6 @@ Tutorials
tutorials/unit_tests
tutorials/mixins
tutorials/pdf_reports
tutorials/dashboards
.. cards::
@ -66,9 +65,3 @@ Tutorials
:target: tutorials/pdf_reports
Use QWeb, Odoo's powerful templating engine, to create custom PDF reports for your documents.
.. card:: Visualize data in dashboards
:target: tutorials/dashboards
Create data visualization dashboards using the enterprise edition "Dashboard" view and
so-called "SQL views".

View File

@ -1,370 +0,0 @@
============================
Visualize data in dashboards
============================
.. important::
This tutorial is an extension of the :doc:`getting_started` tutorial. Make sure you have
completed it and use the `estate` module you have built as a base for the exercises in this
tutorial. Fetch the branch `{BRANCH}-core` from the `technical-training-solutions
<https://github.com/odoo/technical-training-solutions/tree/{BRANCH}-core>`_ repository if you
want to start from a clean base.
The term "Dashboard" is used in Odoo for objects that display data, but involves different
implementations. This tutorial will only focus on the Enterprise view that is used to provide
aggregated data visualization. They can be added as a ``view_mode`` to an existing model (i.e. a
view you can switch to via the view buttons in the top right of a view), but they are also often
used as a view for to a special model customized for data visualization. You may hear these
special views referred to as SQL views.
It is useful to note there is a "Dashboard" app in Odoo Community. This app allows users to create
their own customized view of data, but the customization is only visible to each user and can
only be viewed within the "Dashboard" app. Technically it is possible to make global dashboards
using this ``board`` module, but it is much easier to do as an Enterprise view. Plus it looks nicer
and has extra features not available in ``board``. Some other dashboards within Odoo also exist,
but they are custom made and are beyond the scope of this tutorial.
The documentation related to this topic can be found in :ref:`reference/views/dashboard`.
File Structure
==============
You probably have already guessed that since dashboard views are an Enterprise view, they must have
a dependency on an Enterprise module. The Enterprise module is ``web_dashboard``. Don't forget to
add it to your manifest file! It is standard to add dashboards intended to be used as a
``view_mode`` for one of your module's models (in the ``model`` folder) to the views directory
(i.e. the same file that contains the other views for the same model).
It is standard to create a separate Enterprise module to add extra Enterprise views and features to
a Community module. This is done in a similar manner as the module link technique covered within
:ref:`tutorials/getting_started/14_other_module`. The difference is that instead of linking 2
different modules, we are extending our `estate` module. We do this by creating a new module and
adding both the Community module and its necessary Enterprise module dependencies to its manifest.
You will commonly see "enterprise" in the module's directory name. To keep this tutorial simple, we
will add dashboards to our existing ``estate`` module.
SQL Views have 2 parts: their xml file (don't forget to add it to your manifest file) and their
Python file (don't forget to add it to the appropriate ``__init.py__`` files). The former is the
same format as the ``view_mode`` xml while the latter contains a custom model and SQL code to
populate its fields. It is standard to add SQL view files to the ``report/`` directory. It
is also common to include "report" in the name of the SQL view's files. You may be
wondering why do we put the files in a report directory? We saw earlier that the dashboard is
for data visualization, therefore it is not editable. You can think of dashboards as interactive
reports where you can click on statistics, graphs, and charts to see the specific data contributing
to them. Note it is also standard to store the xml code for :doc:`PDF report templates
<pdf_reports>` in the report directory.
It is expected that your work tree will look something like:
.. code-block:: bash
estate
├── models
│ ├── *.py
│ └── __init__.py
├── report
│ ├── __init__.py
│ ├── estate_report.py
│ └── estate_report_views.xml
├── security
│ └── ir.model.access.csv
├── views
│ ├── *.xml
│ └── estate_property_views.xml
├── __init__.py
└── __manifest__.py
Dashboard View
==============
.. note::
**Goal**: at the end of this section, we will have a new dashboard view that displays
different property statistics.
.. image:: dashboards/simple_dashboard.png
:align: center
:alt: Basic Dashboard view
Dashboards can display data in different ways, including:
* showing an ``aggregate`` of a field
* using aggregated fields in a ``formula``
* using a ``widget``
* using another ``view`` as a subview
There are many useful statistics and visuals we can provide for our real estate example using
these options. A full example to reference while doing the exercises in this section is
`viewable here <https://github.com/odoo/enterprise/blob/6fd3244ae168dc73c348a9c1870796e89d8ef594/crm_enterprise/views/crm_lead_views.xml#L106-L133>`__
(restricted github repository link).
Data
----
To fully enjoy our dashboard view, we will need good test data to populate it. Test data will
allow us to check that the resulting look and statistics are correct. It is a good idea to test
with data that will cover most or all of your expected use cases, but is also easy to verify with
that your statistics are correct. In our goal's case we are looking at count, sum, average,
minimum, and maximum statistics, therefore a good representation set for our dashboard is:
* At least 3 properties with different property types, expected prices, and average living area.
* At least 1 sold property and at least 1 canceled property
If you don't have a set of data like this already, you can either:
* Complete :doc:`define_module_data` (if you haven't done so already) and add the extra cases to
your demo data (you may need to create a new database to load in the demo data).
* Manually create the data in your database.
* Copy this `data file
<https://github.com/odoo/technical-training-solutions/blob/{BRANCH}-K_dashboard/estate/data/estate_demo.xml>`_
into a new directory called ``data`` in your estate module and copy `these lines
<https://github.com/odoo/technical-training-solutions/blob/{BRANCH}-K_dashboard/estate/__manifest__.py#L21-L23>`_
into your __manifest__.py file (you may need to create a new database to load in the demo data).
Click through your database data and make sure it is what you expect. Of course you can add the
data after you write your dashboard code and then test that your view is working as expected.
Aggregations
------------
Building a dashboard view is very similar to what you have previously done in
:ref:`tutorials/getting_started/07_basicviews`. For the dashboard view, we use the `dashboard` root
element and choose from its possible tags (see all the possibilities and their attributes in the
:ref:`reference/views/dashboard` documentation). So a simple dashboard example is:
.. code-block:: xml
<dashboard>
<group>
<aggregate name="min_expected_price" string="Min Expected Price" field="expected_price"
group_operator="min" help="Lowest expected price."/>
</group>
</dashboard>
In this example, ``<group>`` adds styling and ``<aggregate>`` declares an aggregation. We
indicate which ``field`` we want to aggregate, what ``string`` to display with the value, and
how to aggregate it with the `group_operator` attribute. The `group_operator` can use any valid
PostgreSQL aggregate function plus the special Odoo defined ``count_distinct``.
Hopefully you remember how to add views to a window action `view_mode` (hint, it was
covered in :ref:`tutorials/getting_started/06_firstui`). Now let's make some dashboards!
.. exercise:: Make a dashboard view.
- Create a dashboard of aggregated values for the ``estate.property`` model. You can
look at the **Goal** of this section for some inspiration. Remember to check that your
statistics are calculating as you expect and note that the calculated values take into
consideration any applied view filters!
- Bonus: Add in some aggregations that need a `domain` to make sense (remember domains were
also covered in :ref:`tutorials/getting_started/07_basicviews`).
Pie Charts
----------
Adding pie charts to dashboards is a piece of cake using the `<widget>` element. An example is:
.. code-block:: xml
<dashboard>
<group>
<widget name="pie_chart" title="Property Types" attrs="{'groupby': 'property_type_id'}"/>
</group>
</dashboard>
In this example, we indicate that we're using the `pie_chart` widget with the `name` attribute and
the ``title`` for the pie chart, and that we're grouping it by property type.
.. exercise:: Add some pie charts.
- Add the pie charts from the **Goal** of this section to your dashboard. Hint: you will need
to add `'measure': selling_price` to your pie chart `attrs` if you want to show selling
prices grouped by property type.
- Hover over and click on the pie charts to check your charts counts values and don't forget
that filters will also apply to the charts.
- Bonus: Add a domain to your selling price pie chart to only include "sold" properties (i.e.
not "offer_accepted" ones). Note that the `'` will need to be escaped since it is declared
as part of the `attrs`.
Subviews
--------
Similar to how we can use the list view within the form view (we saw this automatically happen for
One2many relationships in :ref:`tutorials/getting_started/08_relations`), we can add other views
within our dashboard view. The most commonly added are the pivot and graph views, but the cohort
view is also an option. A dashboard with only subviews is:
.. code-block:: xml
<dashboard>
<view type="graph"/>
<view type="pivot"/>
</dashboard>
The `ref` attribute can be added to `<view>` elements to use a specific XML id for that view. If
no XML id is provided for a graph or pivot view, then the default view will be used.
The cohort view will not work in the dashboard without a specific XML id. If you have already
created some of these views, then you are welcome to add them to your dashboard! Sample graph and
pivot views are included in the `solution code
<https://github.com/odoo/technical-training-solutions/blob/{BRANCH}-K_dashboard/estate/views/estate_property_views.xml#L169-L191>`_
that you are welcome to use as well.
.. exercise:: Add subviews.
- Add in a graph and a pivot view to your dashboard. Try playing around with the layout of
your subviews in relation to your pie charts and aggregated values and refer to the **Goal**
of this section for an often used layout. Remember to check that your subviews are
displaying your data as expected (and yes, they are also affected by the filters!).
SQL Views
=========
.. warning::
This section expects you to have a basic knowledge of SQL. If you have little to no SQL
knowledge then `this is a good tutorial to start with <https://selectstarsql.com/>`__
and these `exercises <https://www.pgexercises.com/>`__ are good for those who need
a refresher or extra practice.
.. note::
**Goal**: at the end of this section, we will have a new SQL view that displays different
property statistics.
.. image:: dashboards/report_dashboard.png
:align: center
:alt: SQL view
Occasionally we want to show data that goes beyond what our model already has in it. We could add
a lot of stored computed or related fields (non-stored fields cannot be aggregated
or displayed in pie charts), but it would be impractical to store a bunch of fields only for this
purpose. We can instead add a custom SQL view to minimize the computational load and keep our
model clean of unnecessary fields.
Model
-----
We will start with the more difficult part: our special report model. This file starts the same as
any other model, except that we add 2 attributes ``_auto`` and ``_rec_name``::
from odoo import fields, models, tools
class EstateReport(models.Model):
_name = 'estate.report'
_description = "Stock Report"
_rec_name = 'id'
_auto = False
``_auto = False`` indicates that we do not want to store the model in the database, and we will
create a custom table by overriding the ``BaseModel.init()`` method. ``_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). In this case, I left it as 'id' because
our property offers don't have a name. We will need the `tools` import later (i.e.
``odoo/odoo/tools``, which is full of all sorts of useful helper methods you will probably use in
the future). Note that it is standard to include ``report`` in the model's name.
Remember, your new model will need to be added to your security file, as you learned in
:ref:`tutorials/getting_started/05_securityintro`!
Then we define the fields we need for our dashboard the same way as any other model (like you
learned in :ref:`tutorials/getting_started/04_basicmodel`), except that every field is
``readonly=True``. After all, our model is for read-only purposes only.
Now we override the ``BaseModel.init()`` method mentioned earlier::
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()))
We use ``tools.drop_view_if_exists`` to ensure that we don't create a conflicting view and then
execute the SQL query. 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 you will often see at minimum ``_select`` and ``_from`` methods [or something
similar], and of course all these methods will return strings. The columns from the SELECT
will populate our model's fields, so ensure that your column names match your field names
or use alias names that match.
.. exercise:: Create report model.
- Create a report model with the following fields:
========================= ========================= =========================
Field Type Note
========================= ========================= =========================
id Integer Corresponds to ``id`` of ``estate.property.offer``
offer_state Selection Equals ``state`` choices of ``estate.property.offer``
property_id Many2one ``estate.property``
property_state Selection Equals ``state`` choices of ``estate.property``
property_type_id Many2one ``estate.property.type``
========================= ========================= =========================
and write the SQL query necessary to populate the fields (hint, you will need 2 JOINs).
You won't be able to check if your model is correct until we create a view for it, but you are
welcome to check your query directly in your database to see if the results are as you expect.
If you struggle with this exercise, then
`here is an example <https://github.com/odoo/odoo/blob/7417d8fc138b9de550bc631435bcc08628c29bed/addons/crm/report/crm_activity_report.py>`__
to reference.
View
----
Now that we have our model, we can make its dashboard view. There is no difference in how it's made,
except that its file is in the ``report`` folder. Since it is a new model not linked to
any other model, we will also have to add a new menuitem to view our dashboard. Typically, SQL views
are added under a first-level menu called *Reporting* (because it's a report, surprise!). Do you
remember how to add a ``menuitem``? If not, revisit :ref:`tutorials/getting_started/06_firstui`) again.
.. exercise:: Create report view.
- Recreate the dashboard in the **Goal** of this section. Hint: it uses the ``formula`` element,
which we did not need for our previous dashboard.
- Bonus: Create ``list`` and ``form`` views for your new report model so we don't have to see the ugly
defaults when you click on your pie charts.
Extra Tips
----------
**Tip 1** A common mistake in SQL views is not considering the duplication of certain data
due to table JOINs. For example, in our **Goal**, we have a pie chart of the offers' property types.
We may be tempted to add a similar pie chart with a domain to only include canceled properties,
so we think we are only counting the number of canceled properties by property type. In reality, we
are still looking at all the offers per property, so any property with more than 1 offer will be
counted per offer. This example is easily double-checked by clicking on the pie chart to see its
list view:
.. image:: dashboards/report_list_detail.png
:align: center
:alt: Pie chart list view
But for cases such as average aggregations or using a subview such as the pivot view, it is easy to
miss this mistake. It is also easy to miss this mistake when you have insufficient test data.
To add a number of properties canceled by property type pie chart to this
report, we would either have to do a hack (too advanced for this tutorial) or simply exclude it
from this report.
**Tip 2** If you have a field that you do not want as a measure (i.e., in your pivot or
graph views), then you can add ``store=False`` to it, and it will not show.
**Tip 3** If you have a SQL View that depends on context, then instead of overriding
``BaseModel.init()`` set the ``_table_query`` property::
@property
def _table_query(self):
return 'SELECT %s FROM %s' % (self._select(), self._from())
The *select* and *from* methods remain the same.
`Here is an example <{GITHUB_PATH}/addons/account/report/account_invoice_report.py>`__
of a report that depends on the currently selected companies (in a multi-company environment) context to
determine the currency exchange rates to use for accurately displaying amounts when the selected companies
have different currencies.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -50,11 +50,6 @@ Therefore, it is expected that your work tree will look something like this:
├── __init__.py
└── __manifest__.py
Note that you will often see other non-QWeb and non-XML files containing "report" in their name also within
the report folder. These are unrelated to the reports covered in this tutorial and are covered in
the :doc:`dashboards` tutorial. For now you can think of them as customized views that use direct
SQL queries (sometimes referred to as SQL Views).
Don't forget to add whatever files your template and action view will be into to your ``__manifest__.py``.
In this case, you will want to add the files to the ``data`` list and remember that the files listed in a manifest
are loaded sequentially!