Modele i widoki

Podobnie jak strony internetowe, widoki ekranów zaplecza są przechowywane w plikach XML. Nie stosujemy tu jednak języka QWeb (poza definicją kontrolek/widgetów). Wzorce widoków (formularzy etc) - czyli definicje interfejsu użytkownika - są zapisywane w postaci danych wpisywanych do modelu "ir.ui.view". W niniejszym podręczniku można znaleźć wiele tego przykładów. Poniżej kilka zawarto dodatkowych informacji na które warto zwrócić uwagę.

Listy, formularze i drzewa - akcje okna

Definicja akcji otwierającej okno wygląda mniej więcej tak:

<record id="identygikator_akcji" model="ir.actions.act_window">
  <field name="name">dowolny opis</field>
  <field name="res_model">identyfikator.modelu</field>
  <field name="view_id" ref="id_modułu.id_widoku"/>
  <field name="view_type">form</field>
  <field name="view_mode">tree,form</field>
  <field name="target">current</field>
</record>

Pole target może zawierać wartość:

  • new - otwierane jest okienko modalne
  • current - w aktualnym oknie
  • inline - w polu edycji
  • fullscreen - na cały ekran (znikają ikonki i menu poza otwartym oknem)
  • main - w głównym onie (menu i ikonki pozostają)

Ponieważ widoki są związane z modelami, pole view_id jest opcjonalne. Jeśli go nie podamy - zostanie wybrany widok standardowy - formularza.

Te trzy pola: view_id, view_type, view_mode decydują o sposobie wyświetlenia zawartości modelu. Ze względów historycznych wartość view_mode = tree,form oznacza zarówno listę jak i drzewo. Wybór następuje wówczas przez view_type. Gdy ma on wartość form - mamy listę z przyciskami akcji, dodawania i wyszukiwania. Gdy wartość jest tree - mamy drzewo.

Zestawienie możliwych wartości:

view_id (rodzaj widoku) view_type view_mode wynik
tree tree tree drzewo
tree form tree,form lista
tree tree tree,form drzewo
form tree tree drzewo
form form tree,form formularz
form tree tree,form formularz

Rekord akcji okna może zawierać dodatkowo pola kontekst (context - w nawiasach klamrowych {} ) i domenę (domain w nawiasach kwadratowych []).

Akcję okna można wywołać z menu lub przyciskiem formularza. Na przykład (div klasy oe_button_box pojawia się u góry po prawej):

<div class="oe_button_box" name="button_box" position="inside">
 <button class="oe_stat_button" type="action"
    name="%(ident_akcji_okna)d" icon="fa-pencil-square-o" >
     <div class="o_stat_info">
       <span class="o_stat_text"> Wykonaj Akcję Okna </span>
     </div>
  </button>
</div>

Identyfikator ujęty w %( ... )d odnosi się do definicji w XML (a nie do modelu). Należy zwrócić uwagę na to, że przy wywolaniu funkcji modelu ustawiamy atrybut typ="object", a prz wywołaniu akcji (jak wyżej) type="action"!

Pola ukryte

W wielu formularzach są ukrywane dane, których użytkownik nie musi oglądać / zmieniać, ale muszą one być dostępne w zapytaniach (zamieniają się na <input type="hidden">). Definiuje się je przy pomocy własności invisible:

<field name="email" invisible="1"/>

Złożone formularze

W formularzach można zawrzeć tabelki z danymi (ale nie odwrotnie). Pokażemy to na prostym przykładzie dwóch modeli master-details. W modelu nadrzędnym mamy jedno pole - opis oraz odwołanie do tabeli parametrów (details). Jeśli chcemy mieć możliwość edycji tych parametrów w oknie modelu "master", musimy zdefiniować pole Many2one w modelu podrzędnym i One2many w modelu nadrzędnym:

class MasterModel(models.Model):
    _name = 'demo.form.master'
    _description = 'master'

    opis = fields.Char('Opis')
    details_ids = fields.One2many('demo.form.details', 'master_id', 'Parametry')

class DetailModel(models.Model):
    _name = 'demo.form.details'
    _description = 'details'

    master_id = fields.Many2one('demo.form.master', 'Nadrzędny', ondelete='cascade', 
              index=True)
    parametr = fields.Char('Parametry')

W formularzu możemy zdefiniować nie tylko listę parametrów, ale i okienko ich edycji (form) - zob. pole details_ids poniżej:

<record id="demo_master_details.spis" model="ir.ui.view">
  <field name="name">Spis</field>
  <field name="model">demo.form.master</field>
  <field name="arch" type="xml">
    <tree string="lista">
      <field name="opis" />
    </tree>
  </field>
</record>

<record id="demo_master_details.formularz" model="ir.ui.view">
  <field name="name">Szczegóły</field>
  <field name="model">demo.form.master</field>
  <field name="arch" type="xml">
    <form string="Szczegóły">
      <group col="1">
        <field name="opis" />
      </group>
      <notebook>
        <page string="Parametry">
          <field name="details_ids"> 
            <tree string="Lista"> 
              <field name="parametr" />
            </tree>
            <form string="Szczegóły">
              <field name="parametr" />
            </form>
          </field>
        </page>
      </notebook>
    </form>
  </field>
</record>

Poprzez użycie kontekstu (context) możemy filtrować dane w tabelce detail: https://webkul.com/blog/odoo-domain-of-o2m-fields-onchange-of-parent-fields/

Dodatkowe możliwości zyskujemy dzięki użyciu kontrolek / widżetów (widgets). Na przykład w miejsce <field name="details_ids"> możemy wstawić <field name="details_ids" widget="one2many_list">. Spis dostępnych w Odoo widżetów znajdziesz na stronie: https://www.cybrosys.com/blog/widgets-in-odoo.