diff --git a/doc/howtos/backend.rst b/doc/howtos/backend.rst index 7af76db6354..9f5bc5f2209 100644 --- a/doc/howtos/backend.rst +++ b/doc/howtos/backend.rst @@ -839,6 +839,19 @@ float, string), or a function taking a recordset and returning a value:: name = fields.Char(default="Unknown") user_id = fields.Many2one('res.users', default=lambda self: self.env.user) +.. note:: + + The object ``self.env`` gives access to request parameters and other useful + things: + + - ``self.env.cr`` or ``self._cr`` is the database *cursor* object; it is + used for querying the database + - ``self.env.uid`` or ``self._uid`` is the current user's database id + - ``self.env.user`` is the current user's record + - ``self.env.context`` or ``self._context`` is the context dictionary + - ``self.env.ref(xml_id)`` returns the record corresponding to an XML id + - ``self.env[model_name]`` returns an instance of the given model + .. exercise:: Active objects – Default values * Define the start_date default value as today (see @@ -1289,7 +1302,7 @@ policy. Group-based access control mechanisms ------------------------------------- -Groups are created as normal records on the model “res.groups”, and granted +Groups are created as normal records on the model ``res.groups``, and granted menu access via menu definitions. However even without a menu, objects may still be accessible indirectly, so actual object-level permissions (read, write, create, unlink) must be defined for groups. They are usually inserted @@ -1299,7 +1312,7 @@ specific fields on a view or object using the field's groups attribute. Access rights ------------- -Access rights are defined as records of the model “ir.model.access”. Each +Access rights are defined as records of the model ``ir.model.access``. Each access right is associated to a model, a group (or no group for global access), and a set of permissions: read, write, create, unlink. Such access rights are usually created by a CSV file named after its model: @@ -1349,14 +1362,14 @@ Record rules ------------ A record rule restricts the access rights to a subset of records of the given -model. A rule is a record of the model “ir.rule”, and is associated to a +model. A rule is a record of the model ``ir.rule``, and is associated to a model, a number of groups (many2many field), permissions to which the restriction applies, and a domain. The domain specifies to which records the access rights are limited. Here is an example of a rule that prevents the deletion of leads that are not -in state “cancel”. Notice that the value of the field “groups” must follow -the same convention as the method “write” of the ORM. +in state ``cancel``. Notice that the value of the field ``groups`` must follow +the same convention as the method ``write`` of the ORM. .. code-block:: xml @@ -1384,6 +1397,94 @@ the same convention as the method “write” of the ORM. .. patch:: +Wizards +======= + +Wizards describe interactive sessions with the user (or dialog boxes) through +dynamic forms. A wizard is simply a model that extends the class +:class:`~openerp.models.TransientModel` instead of +:class:`~openerp.models.Model`. The class +:class:`~openerp.models.TransientModel` extends :class:`~openerp.models.Model` +and reuse all its existing mechanisms, with the following particularities: + +- Wizard records are not meant to be persistent; they are automatically deleted + from the database after a certain time. This is why they are called + *transient*. +- Wizard models do not require explicit access rights: users have all + permissions on wizard records. +- Wizard records may refer to regular records or wizard records through many2one + fields, but regular records *cannot* refer to wizard records through a + many2one field. + +We want to create a wizard that allow users to create attendees for a particular +session, or for a list of sessions at once. + +.. exercise:: Define the wizard + + Create a wizard model with a many2one relationship with the *Session* + model and a many2many relationship with the *Partner* model. + + .. only:: solutions + + Add a new file ``openacademy/wizard.py``: + + .. patch:: + +Launching wizards +----------------- + +Wizards are launched by ``ir.actions.act_window`` records, with the field +``target`` set to the value ``new``. The latter opens the wizard view into a +popup window. The action may be triggered by a menu item. + +There is another way to launch the wizard: using an ``ir.actions.act_window`` +record like above, but with an extra field ``src_model`` that specifies in the +context of which model the action is available. The wizard will appear in the +contextual actions of the model, above the main view. Because of some internal +hooks in the ORM, such an action is declared in XML with the tag ``act_window``. + +.. code:: xml + + + +Wizards use regular views and their buttons may use the attribute +``special="cancel"`` to close the wizard window without saving. + +.. exercise:: Launch the wizard + + #. Define a form view for the wizard. + #. Add the action to launch it in the context of the *Session* model. + #. Define a default value for the session field in the wizard; use the + context parameter ``self._context`` to retrieve the current session. + + .. only:: solutions + + .. patch:: + +.. exercise:: Register attendees + + Add buttons to the wizard, and implement the corresponding method for adding + the attendees to the given session. + + .. only:: solutions + + .. patch:: + +.. exercise:: Register attendees to multiple sessions + + Modify the wizard model so that attendees can be registered to multiple + sessions. + + .. only:: solutions + + .. patch:: + Internationalization ==================== diff --git a/doc/howtos/backend/exercise-constraint-sql b/doc/howtos/backend/exercise-constraint-sql index dad20c592c7..99ddeabfe9b 100644 --- a/doc/howtos/backend/exercise-constraint-sql +++ b/doc/howtos/backend/exercise-constraint-sql @@ -3,11 +3,11 @@ Index: addons/openacademy/models.py =================================================================== ---- addons.orig/openacademy/models.py 2014-08-26 17:26:07.479783261 +0200 -+++ addons/openacademy/models.py 2014-08-26 17:26:07.475783261 +0200 -@@ -14,6 +14,16 @@ - 'openacademy.session', 'course_id', string="Session") - +--- addons.orig/openacademy/models.py 2014-08-27 14:19:33.099111181 +0200 ++++ addons/openacademy/models.py 2014-08-27 14:20:03.311110732 +0200 +@@ -13,6 +13,16 @@ + session_ids = fields.One2many( + 'openacademy.session', 'course_id', string="Sessions") + _sql_constraints = [ + ('name_description_check', @@ -19,6 +19,6 @@ Index: addons/openacademy/models.py + "The course title must be unique"), + ] + + class Session(models.Model): _name = 'openacademy.session' - diff --git a/doc/howtos/backend/exercise-copy-override b/doc/howtos/backend/exercise-copy-override index c8340f20003..41ed8888adb 100644 --- a/doc/howtos/backend/exercise-copy-override +++ b/doc/howtos/backend/exercise-copy-override @@ -3,11 +3,11 @@ Index: addons/openacademy/models.py =================================================================== ---- addons.orig/openacademy/models.py 2014-08-26 17:26:08.359783248 +0200 -+++ addons/openacademy/models.py 2014-08-26 17:26:08.351783248 +0200 -@@ -14,6 +14,20 @@ - 'openacademy.session', 'course_id', string="Session") - +--- addons.orig/openacademy/models.py 2014-08-27 14:20:12.363110598 +0200 ++++ addons/openacademy/models.py 2014-08-27 14:20:12.359110598 +0200 +@@ -13,6 +13,20 @@ + session_ids = fields.One2many( + 'openacademy.session', 'course_id', string="Sessions") + @api.one + def copy(self, default=None): diff --git a/doc/howtos/backend/exercise-o2m-views b/doc/howtos/backend/exercise-o2m-views deleted file mode 100644 index 9ba227dd641..00000000000 --- a/doc/howtos/backend/exercise-o2m-views +++ /dev/null @@ -1,93 +0,0 @@ -# HG changeset patch -# Parent 1299668a15a9359d4ef77d8f5231816c7de476fa - -Index: addons/openacademy/views/openacademy.xml -=================================================================== ---- addons.orig/openacademy/views/openacademy.xml 2014-08-26 17:26:00.403783366 +0200 -+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:26:00.399783366 +0200 -@@ -9,13 +9,19 @@ - - - -+ - - - - - -- -- This is an example of notebooks -+ -+ -+ -+ -+ -+ -+ - - - -@@ -34,6 +40,18 @@ - - - -+ -+ -+ course.tree -+ openacademy.course -+ -+ -+ -+ -+ -+ -+ -+ - - - -+ -+ -+ session.form -+ openacademy.session -+ -+
-+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
-+
-+
-+ -+ -+ -+ session.tree -+ openacademy.session -+ -+ -+ -+ -+ -+ -+ -+ - - Sessions - openacademy.session diff --git a/doc/howtos/backend/exercise-one2many b/doc/howtos/backend/exercise-one2many index b06733210a1..45409b1b4e6 100644 --- a/doc/howtos/backend/exercise-one2many +++ b/doc/howtos/backend/exercise-one2many @@ -3,21 +3,21 @@ Index: addons/openacademy/models.py =================================================================== ---- addons.orig/openacademy/models.py 2014-08-27 10:37:24.591932036 +0200 -+++ addons/openacademy/models.py 2014-08-27 10:37:24.583932036 +0200 +--- addons.orig/openacademy/models.py 2014-08-27 14:18:59.091111685 +0200 ++++ addons/openacademy/models.py 2014-08-27 14:19:03.259111624 +0200 @@ -10,6 +10,8 @@ responsible_id = fields.Many2one('res.users', ondelete='set null', string="Responsible", index=True) + session_ids = fields.One2many( -+ 'openacademy.session', 'course_id', string="Session") ++ 'openacademy.session', 'course_id', string="Sessions") class Session(models.Model): Index: addons/openacademy/views/openacademy.xml =================================================================== ---- addons.orig/openacademy/views/openacademy.xml 2014-08-27 10:37:24.591932036 +0200 -+++ addons/openacademy/views/openacademy.xml 2014-08-27 10:37:24.583932036 +0200 +--- addons.orig/openacademy/views/openacademy.xml 2014-08-27 14:18:59.091111685 +0200 ++++ addons/openacademy/views/openacademy.xml 2014-08-27 14:18:59.083111686 +0200 @@ -15,8 +15,13 @@ diff --git a/doc/howtos/backend/exercise-wizard b/doc/howtos/backend/exercise-wizard new file mode 100644 index 00000000000..1605185bf05 --- /dev/null +++ b/doc/howtos/backend/exercise-wizard @@ -0,0 +1,24 @@ +Index: addons/openacademy/__init__.py +=================================================================== +--- addons.orig/openacademy/__init__.py 2014-08-27 14:19:23.023111330 +0200 ++++ addons/openacademy/__init__.py 2014-08-27 14:22:25.043108628 +0200 +@@ -2,3 +2,4 @@ + import controllers + import models + import partner ++import wizard +Index: addons/openacademy/wizard.py +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ addons/openacademy/wizard.py 2014-08-27 14:24:39.195106637 +0200 +@@ -0,0 +1,10 @@ ++# -*- coding: utf-8 -*- ++ ++from openerp import models, fields, api ++ ++class Wizard(models.TransientModel): ++ _name = 'openacademy.wizard' ++ ++ session_id = fields.Many2one('openacademy.session', ++ string="Session", required=True) ++ attendee_ids = fields.Many2many('res.partner', string="Attendees") diff --git a/doc/howtos/backend/exercise-wizard-action b/doc/howtos/backend/exercise-wizard-action new file mode 100644 index 00000000000..45a5f5c2a8c --- /dev/null +++ b/doc/howtos/backend/exercise-wizard-action @@ -0,0 +1,30 @@ +Index: addons/openacademy/views/openacademy.xml +=================================================================== +--- addons.orig/openacademy/views/openacademy.xml 2014-08-27 15:01:00.355074258 +0200 ++++ addons/openacademy/views/openacademy.xml 2014-08-27 15:04:45.891070910 +0200 +@@ -245,6 +245,12 @@ + + + ++
++
+ +
+
+Index: addons/openacademy/wizard.py +=================================================================== +--- addons.orig/openacademy/wizard.py 2014-08-27 14:43:02.323090261 +0200 ++++ addons/openacademy/wizard.py 2014-08-27 15:05:28.407070278 +0200 +@@ -11,3 +11,8 @@ + session_id = fields.Many2one('openacademy.session', + string="Session", required=True, default=_default_session) + attendee_ids = fields.Many2many('res.partner', string="Attendees") ++ ++ @api.multi ++ def subscribe(self): ++ self.session_id.attendee_ids |= self.attendee_ids ++ return {} diff --git a/doc/howtos/backend/exercise-wizard-launch b/doc/howtos/backend/exercise-wizard-launch new file mode 100644 index 00000000000..7689bfd243f --- /dev/null +++ b/doc/howtos/backend/exercise-wizard-launch @@ -0,0 +1,46 @@ +Index: addons/openacademy/wizard.py +=================================================================== +--- addons.orig/openacademy/wizard.py 2014-08-27 14:24:39.195106637 +0200 ++++ addons/openacademy/wizard.py 2014-08-27 14:43:02.323090261 +0200 +@@ -5,6 +5,9 @@ + class Wizard(models.TransientModel): + _name = 'openacademy.wizard' + ++ def _default_session(self): ++ return self.env['openacademy.session'].browse(self._context.get('active_id')) ++ + session_id = fields.Many2one('openacademy.session', +- string="Session", required=True) ++ string="Session", required=True, default=_default_session) + attendee_ids = fields.Many2many('res.partner', string="Attendees") +Index: addons/openacademy/views/openacademy.xml +=================================================================== +--- addons.orig/openacademy/views/openacademy.xml 2014-08-27 14:20:50.071110038 +0200 ++++ addons/openacademy/views/openacademy.xml 2014-08-27 15:01:00.355074258 +0200 +@@ -235,5 +235,26 @@ + ++ ++ ++ wizard.form ++ openacademy.wizard ++ ++
++ ++ ++ ++ ++
++
++
++ ++ + + diff --git a/doc/howtos/backend/exercise-wizard-multi b/doc/howtos/backend/exercise-wizard-multi new file mode 100644 index 00000000000..19a21a40df8 --- /dev/null +++ b/doc/howtos/backend/exercise-wizard-multi @@ -0,0 +1,38 @@ +Index: addons/openacademy/views/openacademy.xml +=================================================================== +--- addons.orig/openacademy/views/openacademy.xml 2014-08-27 15:04:45.891070910 +0200 ++++ addons/openacademy/views/openacademy.xml 2014-08-27 15:27:13.919050898 +0200 +@@ -242,7 +242,7 @@ + +
+ +- ++ + + +