How to develop new views in Odoo 10

Canal Odoo / Odoo Experience 2016

By Xavier Morel - Odoo Developer

Compartir en redes sociales

Compartir enlace

Usar vinculo permanente para compartir en redes sociales

Compartir con un amigo

Por favor iniciar sesión para enviar esto document por correo!

Incrustar en tu sitio web

Seleccionar página de inicio

Publicar comentario con dirección de correo electrónico (se requiere confirmación de correo electrónico para publicar comentarios en el sitio web) o por favor iniciar sesión publicar comentario

27. One More Thing

3. Creating a View Anyway, creating a new view (type)

25. Studio No API for Studio integration yet, no Studio for non-standard view types

22. Caveats Not planned => various holes or annoyances Missing pieces of the puzzle can annoy

2. Warning ● Contains JS/web client stuff later on ● Will not cover web client development in general ● Ask web client team or fp for training, documentation, changelogs

12. Client: initial Our empty view ● Action name ● View switcher if multiple views of the same “category” (multi v mono record) ● Search view

26. API ● mono/multi record switch ● API stability ● do_switch_view takes an explicit type requiring specific pairings ● Web team wants API changes (possibly radical) following Studio

24. Drop-in structures ● Validation mixins ● Client helpers/handlers No drop-in validation or helpers/handlers for common (cross-view) Odoo structures, mainly ● Fields ● Buttons

21. Client: View is a Widget ● About it ● Aside from these, view ~ regular widget ● regular widget’s lifecycle ● Regular widget’s tools (willStart/start/$el) ● Regular web client API (QWeb, RPC) ● Regular JS object (vdom)

1. Developing New Views In odoo 10 Xavier Morel EXPERIENCE 2016 Developing new views Technically always possible... by forking the server. But now: new view types in independent isolated modules A bit odd: never planned, never on any roadmap. Just various changes coming together into ability to create views.

16. Client: Control Panel ● Hooking into the Control panel area ● Provides 3 DOM slots ● Associated with view (swapped in/out as view is switched) ● Empty by default ● Names not requirements but strong suggestions ○ matches standard views ○ may be relevant wrt themes ○ In broad sense: corp redesign (actual sidebar), mobile design (buttons need prominence)

23. Post-processing ● access rights ○ this .is_action_enabled( 'edit' ) Some post-processing code works on a whitelist of view types. ● is_action_enabled ○ Basic access rights information ○ Can current user create/write/delete object of the model ○ does not work as server-side information only provided to whitelist of view types

28. Unrelated bonus format_date(date, 'EEE, MMM d', locale) format_date en_US Sat, Oct 8 ● Not related to rest ● Feature I discovered recently ● I18n -> use babel ○ Format dates -> format_date ○ Short date in year (month abbreviation, weekday abbreviation, day of month) ○ Reference locale -> look good

4. Why? ● generic visualisation ● non-technical customisation(-ish) ● integration Why a view? Why a view instead of a client action? ● Generic visualisation over multiple models & records ● Non-technical customisation via view arch ● Web client integration ○ Web client knows the point and can interact more with view Examples: pivot view, geo view (camptocamp), etc...

7. Server: <field> ● groups ● attributes/attrs/modifiers ● fields_get filtering Server: you probably your fields to be called <field> Fair amount of post-processing on fields ● Groups (remove from view if on model, mark as invisible on view) ● Attributes (readonly, invisible and required) and attrs are transferred to modifiers ● Fields_get is merged into fields_view_get then filtered based on what’s in the view Also onchange, but that’s pretty hard to implement ATM

14. Client: other options ● multi_record: false ● mobile_friendly: true ● require_fields: true Other View widget options ● multi_record: views classified in mono v multi records, view switcher only shows one category at a time ○ warning: no way to categorically switch ○ do_switch_view(view_type) ● mobile_friendly: on mobile devices, the first “mobile-friendly” view is shown instead of the first view ● require_fields ○ Needs full fields_get ○ Either to complement existing filtered fields (example: pivot view) ○ or because it doesn’t use <field>

18. Client: Control Panel “sidebar” var Sidebar = require( 'web.Sidebar' ); render_sidebar: function ($node) { var sidebar = new Sidebar( this , {}); sidebar.appendTo($node); } Sidebar section ● Intended as an actions/meta menu ● Helper object provided ● Optional, can hand-roll sidebar “contents”

29. Unrelated bonus format_date(date, 'EEE, MMM d', locale) format_date en_US Sat, Oct 8 es_ES sáb., oct. 8 fr_FR sam., oct. 8 hi_IN शǓन , अÈतू॰ 8 pt_BR sáb, out 8 zh_CN 周六 , 10 月 8 ● Problem: terms translated but format hardcoded ● Different cultures have different ordering & decorations ● Result looks odd as best, nonsensical at worst

5. Server: view type Required class View(models.Model): _inherit = 'ir.ui.view' type = fields.Selection( selection_add=[( 'myview' , "MyView" )] ) class ActWindowView(models.Model): _inherit = 'ir.actions.act_window.view' view_mode = fields.Selection( selection_add=[( 'myview' , "MyView" )] ) First one is the only one actually required. Second one not strictly necessary, most likely good idea. Used when specifying views very explicitly via view_ids.

19. Client: Control Panel pager var Pager = require( 'web.Pager' ); render_pager: function ($node) { var pager = new Pager( this , size, low, page, options); pager.on( 'pager_changed' , this , function (new_state) { // ... }); pager.appendTo($node); } Pager area ● Configurable helper object ● optional

8. Server: validation Optional (but really useful) from import view_validation @view_validation.validate( 'myview' ) def validate_thing(arch): """ Validates a thing """ if arch.find( ".//field[@name='charlie']" ): return True return False Server validation ● Can define validator functions working on lxml etree ● Validator function can do pretty much anything ● Can use elementpath, xpath of traversal to assert specific items are present in the document ● Warning: definition static, loaded even if module not installed. Should not be an issue except multiple views w/ same type.

13. Client: Search View ● do_search: function (domain, context, groupby) { this .set({ 'domain' : domain, 'context' : context, 'groupby' :groupby }); return this ._fetch(); } ● searchable: false Hook search view, or disable it ● If searchable view, view manager will invoke do_search (can be async) ● Passed domain, context and groupby compiled from action and search view ○ Groupby are extracted from contexts for you ● Default view is searchable with no-op do_search ● Non-searchable views don’t get a search view shown at all (e.g. form view)

6. Server: view arch < record id ="view_myview" model ="ir.ui.view" > < field name ="name" >My View</ field > < field name ="model" >res.users</ field > < field name ="arch" type ="xml" > < myview >???</ myview > </ field > </ record > Congratulation your server-side work is done and you can create your view. Content is whatever you want. Which means it’s not that useful, so you’re not actually done

10. Server: base methods Optional (avoid unless necessary) class Base(models.AbstractModel): _inherit = 'base' myfield = fields.Boolean( "My Field" ) @api.multi def myread(self): """ ... """ ● A “base” model has been introduced, which you can extend ● Every other model inherits from base ● Odoo inheritance now properly dynamic, properties added to an inherited model will be reflected on all inheritors even if created before extension ● Avoid unless really necessary ○ Especially fields as they can have odd side-effects (storage, required fields on db upgrade) ○ Methods pollute ns a bit but less problematic ● Warning: base is an abstract model, bad things happen otherwise

30. Unrelated bonus format_skeleton('MMMEEEdd', date, locale) format_date format_skeleton en_US Sat, Oct 8 Sat, Oct 8 es_ES sáb., oct. 8 sáb., 8 oct. fr_FR sam., oct. 8 sam. 8 oct. hi_IN शǓन , अÈतू॰ 8 शǓन , 8 अÈतू॰ pt_BR sáb, out 8 sáb, 8 de out zh_CN 周六 , 10 月 8 10 月 8 日周六 ● Format_skeleton takes pattern of terms to include ● Locale-dependent mapping to formatted pattern ● Babel 2.3 (April 8th, 2016)

17. Client: Control Panel buttons render_buttons: function ($node) { var $buttons = $( '<div/>' ); $buttons.append( QWeb.render( "MyView.buttons" , { 'widget' : this }) ).on( 'click' , '.my_button_create' , this .on_create) .on( 'click' , '.my_button_import' , this .on_import); $node.append($buttons); } Buttons zone ● Intended for action buttons ● Add content to DOM and hook events on them ● May want to keep references to buttons ○ enable/disable them ○ show/hide them

20. Client: View Widget ● fields_view ● model ● dataset ● do_execute_action ● do_switch_view ● do_show View Widget services ● Fields_view is content of fields_view_get ○ Passed to init method (3rd arg) ○ Available as `this.fields_view` ● Model ○ Setup with the action’s model ○ For RPC ● Cursor-ish, mostly setting up “all records” and “current record” for form ● do_execute_action ○ Asks ancestor action manager to execute an action based on descriptor ○ Mostly useful for buttons ● do_switch_view ○ Takes view type ○ Tries to switch to that view type ● do_show ○ Called when view is shown (~switched to)

9. Server: lxml validators Optional (but really useful) def validate_thing(arch): with misc.file_open(os.path.join( 'my_module' , 'views' , 'myview.rng' )) as f: validator = etree.RelaxNG(etree.parse(f)) if validator.validate(arch): return True for error in validator.error_log: logger.error(error) return False LXML validators Anything includes LXML’s various validators, such as RelaxNG (used by Odoo for XML import validation) ● Parse & load relaxng file ● Validate etree ● Print out validation error ● Could just return `validate` result, but error messages on validation failure can be useful ● Lxml also supports Schematron, DTD and XML Schemas

11. Client: declare widget odoo.define( 'x_test.main' , function (require) { var core = require( 'web.core' ); var View = require( 'web.View' ); var _lt = core._lt; var MyView= View.extend({ icon: 'fa-cogs' , display_name: _lt( "My View" ), }); core.view_registry.add( 'myview' , MyView); }); Client: declare widget ● Subtype of the abstract web.View object ● New type must be added to view registry ● Doesn’t do anything at this point ● Technically display_name and icon not required ○ But default values are empty string and question mark ○ Icon and display_name used for view switcher button (icon and tooltip respectively)

15. Client: URL & history ● this .do_push_state({}); ● do_show: function () { this .do_push_state({}); return this ._super(); } ● reload_content: function () { // ... this .do_push_state({ min: this .current_min, limit: this ._limit }); } URL and history handling ● do_push_state (method of View) will add a new state item to the stack ○ ViewManager automatically adds current view *type* ○ Which is why pushing an empty state is useful (adds new state transitioning to current view type) ● Usually called on do_show to update current view_type ● Can pass map of additional values to store in the URL (and history) e.g. ○ pagination info in list view (when updating list) ○ current record id in form view (when loading record) ● Can call at any moment to further update values


  • 693 Vistas totales
  • 489 Vistas del sitio web
  • 204 Vistas incrustadas


  • 0 Acciones Sociales
  • 0 Me gusta
  • 0 No me gusta
  • 0 Comentarios

Veces compartido

  • 0 Facebook
  • 0 Twitter
  • 0 LinkedIn
  • 0 Google+