Browse Source
[ADD] module module_uninstall_check (#816)
[ADD] module module_uninstall_check (#816)
* [ADD] module module_uninstall_check * [ADD] database size information + [IMP] various. cortesy @jcdrubay * [IMP] make module working if model are present but code is not present * [FIX] pylint and readme rile * [FIX] flake8 * [FIX] pylintpull/1364/head
Sylvain LE GAL
7 years ago
committed by
Dave Lasley
14 changed files with 662 additions and 0 deletions
-
103module_uninstall_check/README.rst
-
2module_uninstall_check/__init__.py
-
23module_uninstall_check/__openerp__.py
-
15module_uninstall_check/demo/res_groups.xml
-
188module_uninstall_check/i18n/fr.po
-
BINmodule_uninstall_check/static/description/module_form.png
-
BINmodule_uninstall_check/static/description/sale_margin_uninstallation.png
-
BINmodule_uninstall_check/static/description/sale_uninstallation.png
-
22module_uninstall_check/views/ir_module_module.xml
-
3module_uninstall_check/wizards/__init__.py
-
18module_uninstall_check/wizards/action.xml
-
117module_uninstall_check/wizards/wizard_module_uninstall.py
-
49module_uninstall_check/wizards/wizard_module_uninstall.xml
-
122module_uninstall_check/wizards/wizard_module_uninstall_line.py
@ -0,0 +1,103 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
============================ |
|||
Module Uninstallation Checks |
|||
============================ |
|||
|
|||
This module extends the functionality of base module, to improve modules |
|||
uninstallation process. |
|||
|
|||
It provides an extra view, on module form to display which models (SQL tables) |
|||
and which fields (SQL columns) will be dropped, if the selected module is |
|||
uninstalled. |
|||
|
|||
Technical Note |
|||
============== |
|||
|
|||
This module uses postgreSQL native column like reltuples in pg_class that |
|||
provides approximative rows quantity. To have a precise value, please |
|||
run first the following code: |
|||
|
|||
.. code-block:: sql |
|||
|
|||
REINDEX DATABASE my_database_name; |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
To use this module, you need to: |
|||
|
|||
#. Go to Settings / Modules / Local Modules |
|||
#. Select an installed module |
|||
#. Click on the button 'Uninstallation Impact' |
|||
|
|||
.. figure:: /module_uninstall_check/static/description/module_form.png |
|||
:width: 800 px |
|||
|
|||
* Sample, selecting sale_margin module |
|||
|
|||
.. figure:: /module_uninstall_check/static/description/sale_margin_uninstallation.png |
|||
:width: 800 px |
|||
|
|||
* Sample, selecting sale_stock module, when sale_margin is installed |
|||
|
|||
.. figure:: /module_uninstall_check/static/description/sale_uninstallation.png |
|||
:width: 800 px |
|||
|
|||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
|||
:alt: Try me on Runbot |
|||
:target: https://runbot.odoo-community.org/runbot/149/8.0 |
|||
|
|||
Known issues / Roadmap |
|||
====================== |
|||
|
|||
* In some cases, we want to uninstall a module, but prevent some data deletion. |
|||
This can happen if we want to keep some datas after uninstallation or if the |
|||
data moved into another module after a refactoring. |
|||
|
|||
This module could implement such feature, adding extra feature on wizard lines, |
|||
deleting or renaming xml ids. |
|||
|
|||
* For the time being, wizard displays size used for models in database. It |
|||
could be interesting to know the space released by the deletion of a column. |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues |
|||
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please |
|||
check there if your issue has already been reported. If you spotted it first, |
|||
help us smash it by providing detailed and welcomed feedback. |
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
|
|||
Funders |
|||
------- |
|||
|
|||
The development of this module has been financially supported by: |
|||
|
|||
* GRAP, Groupement Régional Alimentaire de Proximité (http://www.grap.coop) |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
.. image:: https://odoo-community.org/logo.png |
|||
:alt: Odoo Community Association |
|||
:target: https://odoo-community.org |
|||
|
|||
This module is maintained by the OCA. |
|||
|
|||
OCA, or the Odoo Community Association, is a nonprofit organization whose |
|||
mission is to support the collaborative development of Odoo features and |
|||
promote its widespread use. |
|||
|
|||
To contribute to this module, please visit https://odoo-community.org. |
|||
|
@ -0,0 +1,2 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from . import wizards |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
{ |
|||
"name": "Module Uninstall Check", |
|||
"summary": "Add Extra Checks before uninstallation of modules", |
|||
"version": "8.0.1.0.0", |
|||
"category": "Base", |
|||
"website": "https://odoo-community.org/", |
|||
"author": "GRAP, Odoo Community Association (OCA)", |
|||
"license": "AGPL-3", |
|||
"installable": True, |
|||
"depends": [ |
|||
'base', |
|||
], |
|||
"data": [ |
|||
'wizards/wizard_module_uninstall.xml', |
|||
'wizards/action.xml', |
|||
'views/ir_module_module.xml', |
|||
], |
|||
"demo": [ |
|||
'demo/res_groups.xml', |
|||
], |
|||
} |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) |
|||
@author Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
--> |
|||
|
|||
<openerp><data> |
|||
|
|||
<record id="base.group_no_one" model="res.groups"> |
|||
<field name="users" eval="[ |
|||
(4, ref('base.user_root'))]" /> |
|||
</record> |
|||
|
|||
</data></openerp> |
@ -0,0 +1,188 @@ |
|||
|
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * module_uninstall_check |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 8.0\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2017-04-20 20:14+0000\n" |
|||
"PO-Revision-Date: 2017-04-20 20:14+0000\n" |
|||
"Last-Translator: <>\n" |
|||
"Language-Team: \n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: \n" |
|||
"Plural-Forms: \n" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: view:wizard.module.uninstall:module_uninstall_check.view_wizard_module_uninstall_form |
|||
msgid "Cancel" |
|||
msgstr "Cancel" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: help:wizard.module.uninstall,module_id:0 |
|||
msgid "Choose a module. The wizard will display all the models and fields linked to that module, that will be dropped, if selected module is uninstalled.\n" |
|||
" Note : Only Non Transient items will be displayed" |
|||
msgstr "Choisissez un module. L'assistant va afficher tous les modèles et tous les champs associés à ce module, et qui seront supprimés, si le module sélectionné est désinstallé.\n" |
|||
" Note: Seulement les éléments persistants en base de données seront affichés" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,create_uid:0 |
|||
#: field:wizard.module.uninstall.line,create_uid:0 |
|||
msgid "Created by" |
|||
msgstr "Créé par" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,create_date:0 |
|||
#: field:wizard.module.uninstall.line,create_date:0 |
|||
msgid "Created on" |
|||
msgstr "Créé le" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,display_name:0 |
|||
#: field:wizard.module.uninstall.line,display_name:0 |
|||
msgid "Display Name" |
|||
msgstr "Nom affiché" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: selection:wizard.module.uninstall.line,type:0 |
|||
msgid "Field" |
|||
msgstr "Champ" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,field_model_name:0 |
|||
msgid "Field Model Name" |
|||
msgstr "Nom du modèle du champ" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,field_name:0 |
|||
msgid "Field Name" |
|||
msgstr "Nom du champ" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,field_ttype:0 |
|||
msgid "Field Type" |
|||
msgstr "Type du champ" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,field_id:0 |
|||
msgid "Field id" |
|||
msgstr "Field id" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,field_line_ids:0 |
|||
msgid "Field line ids" |
|||
msgstr "Field line ids" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,id:0 |
|||
#: field:wizard.module.uninstall.line,id:0 |
|||
msgid "ID" |
|||
msgstr "ID" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,module_ids:0 |
|||
msgid "Impacted modules" |
|||
msgstr "Modules impactés" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,module_qty:0 |
|||
msgid "Impacted modules Quantity" |
|||
msgstr "Nombre de modules impactés" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,__last_update:0 |
|||
#: field:wizard.module.uninstall.line,__last_update:0 |
|||
msgid "Last Modified on" |
|||
msgstr "Dernière modification le" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,write_uid:0 |
|||
#: field:wizard.module.uninstall.line,write_uid:0 |
|||
msgid "Last Updated by" |
|||
msgstr "Dernière mise à jour par" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,write_date:0 |
|||
#: field:wizard.module.uninstall.line,write_date:0 |
|||
msgid "Last Updated on" |
|||
msgstr "Dernière mise à jour le" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: selection:wizard.module.uninstall.line,type:0 |
|||
msgid "Model" |
|||
msgstr "Modèle" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,model_name:0 |
|||
msgid "Model Name" |
|||
msgstr "Nom du modèle" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,model_id:0 |
|||
msgid "Model id" |
|||
msgstr "Model id" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,model_line_ids:0 |
|||
msgid "Model line ids" |
|||
msgstr "Model line ids" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,module_id:0 |
|||
msgid "Module" |
|||
msgstr "Module" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall,module_name:0 |
|||
msgid "Module Name" |
|||
msgstr "Nom du module" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: help:wizard.module.uninstall,module_ids:0 |
|||
msgid "Modules list that will be uninstalled by dependency" |
|||
msgstr "Liste des modules qui seront désinstallés par dépendance" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: view:wizard.module.uninstall:module_uninstall_check.view_wizard_module_uninstall_form |
|||
msgid "Related Fields" |
|||
msgstr "Champs associés" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: view:wizard.module.uninstall:module_uninstall_check.view_wizard_module_uninstall_form |
|||
msgid "Related Models" |
|||
msgstr "Modèle associés" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,model_row_qty:0 |
|||
msgid "Row Quantity" |
|||
msgstr "Nombre de lignes" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: view:wizard.module.uninstall:module_uninstall_check.view_wizard_module_uninstall_form |
|||
msgid "System Update" |
|||
msgstr "System Update" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: view:wizard.module.uninstall:module_uninstall_check.view_wizard_module_uninstall_form |
|||
msgid "The following models and fields will be dropped if uninstallation of the selected module is done" |
|||
msgstr "Les modèles et les champs suivants seront supprimés si la désinstallation du module sélectionné est réalisé" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,type:0 |
|||
msgid "Type" |
|||
msgstr "Type" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: model:ir.actions.act_window,name:module_uninstall_check.action_wizard_module_uninstall |
|||
#: view:ir.module.module:module_uninstall_check.view_ir_module_module_form |
|||
msgid "Uninstallation Impact" |
|||
msgstr "Impact de la désinstallation" |
|||
|
|||
#. module: module_uninstall_check |
|||
#: field:wizard.module.uninstall.line,wizard_id:0 |
|||
msgid "Wizard id" |
|||
msgstr "Wizard id" |
|||
|
After Width: 760 | Height: 228 | Size: 29 KiB |
After Width: 888 | Height: 548 | Size: 33 KiB |
After Width: 706 | Height: 719 | Size: 64 KiB |
@ -0,0 +1,22 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
|||
@author Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
--> |
|||
|
|||
<openerp><data> |
|||
|
|||
<record id="ir_module_module_view_form" model="ir.ui.view"> |
|||
<field name="model">ir.module.module</field> |
|||
<field name="inherit_id" ref="base.module_form"/> |
|||
<field name="arch" type="xml"> |
|||
<button name="button_install_cancel" position="after"> |
|||
<button name="%(wizard_module_uninstall_action)d" |
|||
type="action" string="Uninstallation Impact" |
|||
attrs="{'invisible': [('state', 'in', ('uninstalled', 'uninstallable'))]}"/> |
|||
</button> |
|||
</field> |
|||
</record> |
|||
|
|||
</data></openerp> |
@ -0,0 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from . import wizard_module_uninstall |
|||
from . import wizard_module_uninstall_line |
@ -0,0 +1,18 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
Copyright (C) 2016-Today GRAP (http://www.grap.coop) |
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
--> |
|||
|
|||
<openerp><data> |
|||
|
|||
<record id="wizard_module_uninstall_action" model="ir.actions.act_window"> |
|||
<field name="name">Uninstallation Impact</field> |
|||
<field name="res_model">wizard.module.uninstall</field> |
|||
<field name="view_type">form</field> |
|||
<field name="view_mode">form</field> |
|||
<field name="target">new</field> |
|||
</record> |
|||
|
|||
</data></openerp> |
@ -0,0 +1,117 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
|||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from openerp import api, fields, models |
|||
|
|||
|
|||
class WizardModuleUninstall(models.TransientModel): |
|||
_name = 'wizard.module.uninstall' |
|||
|
|||
def _default_module_id(self): |
|||
return self._context.get('active_id', False) |
|||
|
|||
module_id = fields.Many2one( |
|||
string='Module', comodel_name='ir.module.module', required=True, |
|||
domain=[('state', 'not in', ['uninstalled', 'uninstallable'])], |
|||
default=_default_module_id, |
|||
help="Choose a module. The wizard will display all the models" |
|||
" and fields linked to that module, that will be dropped," |
|||
" if selected module is uninstalled.\n" |
|||
" Note : Only Non Transient items will be displayed") |
|||
|
|||
module_ids = fields.Many2many( |
|||
string='Impacted modules', compute='_compute_module_ids', |
|||
multi='module_ids', |
|||
comodel_name='ir.module.module', readonly=True, |
|||
help="Modules list that will be uninstalled by dependency") |
|||
|
|||
module_qty = fields.Integer( |
|||
string='Impacted modules Quantity', compute='_compute_module_ids', |
|||
multi='module_ids', readonly=True) |
|||
|
|||
module_name = fields.Char( |
|||
string='Module Name', related='module_id.name', readonly=True) |
|||
|
|||
model_line_ids = fields.One2many( |
|||
comodel_name='wizard.module.uninstall.line', readonly=True, |
|||
inverse_name='wizard_id', domain=[('line_type', '=', 'model')]) |
|||
|
|||
field_line_ids = fields.One2many( |
|||
comodel_name='wizard.module.uninstall.line', readonly=True, |
|||
inverse_name='wizard_id', domain=[('line_type', '=', 'field')]) |
|||
|
|||
# Compute Section |
|||
@api.multi |
|||
@api.depends('module_id') |
|||
def _compute_module_ids(self): |
|||
for wizard in self: |
|||
if wizard.module_id: |
|||
res = wizard.module_id.downstream_dependencies() |
|||
wizard.module_ids = res |
|||
wizard.module_qty = len(res) |
|||
else: |
|||
wizard.module_ids = False |
|||
wizard.module_qty = 0 |
|||
|
|||
# OnChange Section |
|||
@api.multi |
|||
@api.onchange('module_id') |
|||
def onchange_module_id(self): |
|||
model_data_obj = self.env['ir.model.data'] |
|||
model_obj = self.env['ir.model'] |
|||
field_obj = self.env['ir.model.fields'] |
|||
|
|||
for wizard in self: |
|||
wizard.model_line_ids = False |
|||
wizard.field_line_ids = False |
|||
|
|||
for wizard in self: |
|||
model_ids = [] |
|||
module_names = wizard.module_ids.mapped('name')\ |
|||
+ [wizard.module_id.name] |
|||
# Get Models |
|||
models_data = [] |
|||
all_model_ids = model_data_obj.search([ |
|||
('module', 'in', module_names), |
|||
('model', '=', 'ir.model')]).mapped('res_id') |
|||
all_model_ids = list(set(all_model_ids)) |
|||
for model in model_obj.browse(all_model_ids).filtered( |
|||
lambda x: not x.osv_memory): |
|||
# Filter models that are not associated to other modules, |
|||
# and that will be removed, if the selected module is |
|||
# uninstalled |
|||
other_declarations = model_data_obj.search([ |
|||
('module', 'not in', module_names), |
|||
('model', '=', 'ir.model'), |
|||
('res_id', '=', model.id)]) |
|||
if not len(other_declarations): |
|||
models_data.append((0, 0, { |
|||
'line_type': 'model', |
|||
'model_id': model.id, |
|||
})) |
|||
model_ids.append(model.id) |
|||
wizard.model_line_ids = models_data |
|||
|
|||
# Get Fields |
|||
fields_data = [] |
|||
all_field_ids = model_data_obj.search([ |
|||
('module', 'in', module_names), |
|||
('model', '=', 'ir.model.fields')]).mapped('res_id') |
|||
for field in field_obj.search([ |
|||
('id', 'in', all_field_ids), |
|||
('model_id', 'not in', model_ids), |
|||
('ttype', 'not in', ['one2many'])], |
|||
order='model_id, name'): |
|||
other_declarations = model_data_obj.search([ |
|||
('module', 'not in', module_names), |
|||
('model', '=', 'ir.model.field'), |
|||
('res_id', '=', model.id)]) |
|||
if not len(other_declarations)\ |
|||
and not field.model_id.osv_memory: |
|||
fields_data.append((0, 0, { |
|||
'line_type': 'field', |
|||
'field_id': field.id, |
|||
})) |
|||
wizard.field_line_ids = fields_data |
@ -0,0 +1,49 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
|||
@author Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
--> |
|||
|
|||
<openerp><data> |
|||
|
|||
<record id="wizard_module_uninstall_view_form" model="ir.ui.view"> |
|||
<field name="model">wizard.module.uninstall</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="System Update"> |
|||
<p>The following models and fields will be dropped if uninstallation of the selected module is done</p> |
|||
<field name="module_qty" invisible="1"/> |
|||
<group col="4"> |
|||
<field name="module_id"/> |
|||
<field name="module_name" /> |
|||
<field name="module_ids" widget="many2many_tags" attrs="{'invisible': [('module_qty', '=', 0)]}" colspan="4"/> |
|||
</group> |
|||
<separator string="Related Models"/> |
|||
<field name="model_line_ids" notitle="1" colspan="4" attrs="{'invisible': [('model_line_ids', '=', False)]}"> |
|||
<tree colors="gray: db_size==0; brown:db_type=='v'"> |
|||
<field name="db_type" invisible="1"/> |
|||
<field name="model_id" /> |
|||
<field name="model_name" /> |
|||
<field name="model_row_qty" /> |
|||
<field name="table_size" sum="Total"/> |
|||
<field name="index_size" sum="Total"/> |
|||
<field name="db_size" sum="Total"/> |
|||
</tree> |
|||
</field> |
|||
<separator string="Related Fields"/> |
|||
<field name="field_line_ids" notitle="1" colspan="4" attrs="{'invisible': [('field_line_ids', '=', False)]}"> |
|||
<tree> |
|||
<field name="field_id" /> |
|||
<field name="field_model_name" /> |
|||
<field name="field_name" /> |
|||
<field name="field_ttype" /> |
|||
</tree> |
|||
</field> |
|||
<footer> |
|||
<button special="cancel" string="Cancel"/> |
|||
</footer> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
</data></openerp> |
@ -0,0 +1,122 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
|||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import logging |
|||
|
|||
from openerp import api, fields, models |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class WizardModuleUninstallLine(models.TransientModel): |
|||
_name = 'wizard.module.uninstall.line' |
|||
|
|||
LINE_TYPE_SELECTION = [ |
|||
('model', 'Model'), |
|||
('field', 'Field'), |
|||
] |
|||
|
|||
DB_TYPE_SELECTION = [ |
|||
('', 'Unknown Type'), |
|||
('r', 'Ordinary Table'), |
|||
('i', 'Index'), |
|||
('S', 'Sequence'), |
|||
('v', 'view'), |
|||
('c', 'Composite Type'), |
|||
('t', 'TOAST table'), |
|||
] |
|||
|
|||
wizard_id = fields.Many2one( |
|||
comodel_name='wizard.module.uninstall', required=True) |
|||
|
|||
line_type = fields.Selection( |
|||
selection=LINE_TYPE_SELECTION, required=True) |
|||
|
|||
model_id = fields.Many2one(comodel_name='ir.model', readonly=True) |
|||
|
|||
model_name = fields.Char( |
|||
string='Model Name', related='model_id.model', readonly=True) |
|||
|
|||
table_size = fields.Integer( |
|||
string='Table Size (KB)', compute='_compute_database', |
|||
multi='database', store=True) |
|||
|
|||
index_size = fields.Integer( |
|||
string='Indexes Size (KB)', compute='_compute_database', |
|||
multi='database', store=True) |
|||
|
|||
db_type = fields.Selection( |
|||
selection=DB_TYPE_SELECTION, compute='_compute_database', |
|||
multi='database', store=True) |
|||
|
|||
db_size = fields.Integer( |
|||
string='Total DB Size (KB)', compute='_compute_database', |
|||
multi='database', store=True) |
|||
|
|||
model_row_qty = fields.Integer( |
|||
string='Rows Quantity', compute='_compute_database', multi='database', |
|||
store=True, |
|||
help="The approximate value of the number of records in the database," |
|||
" based on the PostgreSQL column 'reltuples'.\n You should reindex" |
|||
" your database, to have a more precise value\n\n" |
|||
" 'REINDEX database your_database_name;'") |
|||
|
|||
field_id = fields.Many2one(comodel_name='ir.model.fields', readonly=True) |
|||
|
|||
field_name = fields.Char( |
|||
string='Field Name', related='field_id.name', readonly=True) |
|||
|
|||
field_ttype = fields.Selection( |
|||
string='Field Type', related='field_id.ttype', readonly=True) |
|||
|
|||
field_model_name = fields.Char( |
|||
string='Field Model Name', related='field_id.model_id.model', |
|||
readonly=True) |
|||
|
|||
@api.multi |
|||
@api.depends('model_id', 'line_type') |
|||
def _compute_database(self): |
|||
table_names = [] |
|||
for line in self.filtered(lambda x: x.model_id): |
|||
model_obj = self.env.registry.get(line.model_id.model, False) |
|||
if model_obj: |
|||
table_names.append(model_obj._table) |
|||
else: |
|||
# Try to guess table name, replacing "." by "_" |
|||
table_names.append(line.model_id.model.replace('.', '_')) |
|||
|
|||
# Get Relation Informations |
|||
req = ( |
|||
"SELECT" |
|||
" table_name," |
|||
" row_qty," |
|||
" db_type," |
|||
" pg_table_size(table_name::regclass::oid) AS table_size," |
|||
" pg_indexes_size(table_name::regclass::oid) AS index_size," |
|||
" pg_total_relation_size(table_name::regclass::oid) AS db_size" |
|||
" FROM (" |
|||
" SELECT" |
|||
" relname AS table_name," |
|||
" reltuples AS row_qty," |
|||
" relkind as db_type" |
|||
" FROM pg_class" |
|||
" WHERE relname IN %s) AS tmp;" |
|||
) |
|||
self.env.cr.execute(req, (tuple(table_names),)) |
|||
res = self.env.cr.fetchall() |
|||
table_res = {x[0]: (x[1], x[2], x[3], x[4], x[5]) for x in res} |
|||
for line in self: |
|||
model_obj = self.env.registry.get(line.model_id.model, False) |
|||
if model_obj: |
|||
table_name = model_obj._table |
|||
else: |
|||
# Try to guess table name, replacing "." by "_" |
|||
table_name = line.model_id.model.replace('.', '_') |
|||
res = table_res.get(table_name, (0, '', 0, 0, 0)) |
|||
line.model_row_qty = res[0] |
|||
line.db_type = res[1] |
|||
line.table_size = res[2] / 1024 |
|||
line.index_size = res[3] / 1024 |
|||
line.db_size = res[4] / 1024 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue