.. _tutorial-module-states: Add dynamic state to fields =========================== Sometimes you want to make fields read-only, invisible or required under certain conditions. This can be achieved using the :attr:`~trytond.model.fields.Field.states` attribute of the :class:`~trytond.model.fields.Field`. It is a dictionary with the keys ``readonly``, ``invisible`` and ``required``. The values are :class:`~trytond.pyson.PYSON` statements that are evaluated with the values of the record. In our example we make some fields read-only when the record is not in the state ``opportunity``, the "End Date" required for the ``converted`` and ``lost`` state and make the comment invisible if empty: .. code-block:: python class Opportunity(...): ... description = fields.Char( "Description", required=True, states={ 'readonly': Eval('state') != 'draft', }) start_date = fields.Date( "Start Date", required=True, states={ 'readonly': Eval('state') != 'draft', }) end_date = fields.Date( "End Date", states={ 'readonly': Eval('state') != 'draft', 'required': Eval('state').in_(['converted', 'lost']), }) party = fields.Many2One( 'party.party', "Party", required=True, states={ 'readonly': Eval('state') != 'draft', }) address = fields.Many2One( 'party.address', "Address", domain=[ ('party', '=', Eval('party')), ], states={ 'readonly': Eval('state') != 'draft', }) comment = fields.Text( "Comment", states={ 'readonly': Eval('state') != 'draft', 'invisible': ( (Eval('state') != 'draft') & ~Eval('comment')), }) It is also possible to set the ``readonly``, ``invisible`` and ``icon`` states on the :attr:`~trytond.model.ModelView._buttons`. So we can make invisible each button for the state in which the transition is not available: .. code-block:: python class Opportunity(ModelSQL, ModelView): ... @classmethod def __setup__(cls): ... cls._buttons.update({ 'convert': { 'invisible': Eval('state') != 'draft', 'depends': ['state'], }, 'lost': { 'invisible': Eval('state') != 'draft', 'depends': ['state'], }, }) .. note:: The fields in :class:`~trytond.pyson.Eval` statement must be added to the ``depends`` attribute to register the field on which the states depend. Exercise -------- As exercise we let you define the state for the button that reset to ``draft`` state. Let's :ref:`extend the party model <tutorial-module-extend>`.