Skip to content

Odoo portal sort by: Step-by-Step Tutorial for Odoo 17

  • Odoo
add sort Odoo portal

First, Odoo portal sort by option lets you give users full control over record order. Moreover, you can improve portal sorting in Odoo by adding custom “Sort By” fields. Meanwhile, this tutorial guides you through each step to add sort options in Odoo 17 portal. Consequently, you will learn how to override the portal controller, define sorting choices, update XML templates, and test the feature. Furthermore, you will find code examples, clear explanations, and an outgoing link to the official Odoo docs for deeper insight: https://www.odoo.com/documentation/17.0/webframework/portal.html

Prerequisites and Environment Setup for Portal Sorting

First, set up your development environment. Then, confirm that you run Odoo 17 on your local or staging server. Next, ensure you have a custom addon (for example, odoo_discussions) in your Odoo addons path. Meanwhile, activate developer mode in Odoo and restart your Odoo service before each code change. Finally, install your custom module from Apps.

Required Tools and Modules

  • Odoo 17 server running locally or on a staging VM
  • A code editor (VS Code, PyCharm, or similar)
  • Access to addon paths and the ability to restart Odoo service
  • Basic Python and XML knowledge

Directory Structure Overview

Meanwhile, your custom addon (odoo_discussions) should contain at least:

odoo_discussions/
│
├── __init__.py
├── __manifest__.py
├── controllers/
│   ├── __init__.py
│   └── portal.py         ← custom portal controllers
├── models/
│   └── __init__.py
├── views/
│   └── templates.xml     ← portal templates
└── static/

Consequently, you will place controller code in controllers/portal.py and template code in views/templates.xml.

Step 1 – Override the Portal Sale Order Controller

First, you override Odoo’s standard portal sale order controller to handle a new sortby parameter. Then, you pass that parameter to your custom sorting logic.

portal sale order override code

# File: odoo_discussions/controllers/portal.py

from odoo import http
from odoo.http import request
from odoo.addons.portal.controllers import portal

class CustomerPortal(portal.CustomerPortal):
    def _prepare_sale_portal_rendering_values(
        self, page=1, date_begin=None, date_end=None,
        sortby=None, quotation_page=False, **kwargs
    ):
        SaleOrder = request.env['sale.order']
        # First, set default sort field
        if not sortby:
            sortby = 'date'
        partner = request.env.user.partner_id
        values = self._prepare_portal_layout_values()
        # Then, choose domain and URL based on page type
        if quotation_page:
            url = "/my/quotes"
            domain = self._prepare_quotations_domain(partner)
        else:
            url = "/my/orders"
            domain = self._prepare_orders_domain(partner)
        # Next, get available sorting options
        searchbar_sortings = self._get_sale_searchbar_sortings()
        # Then, find the SQL ORDER clause
        sort_order = searchbar_sortings[sortby]['order']
        # Meanwhile, filter by date range if provided
        if date_begin and date_end:
            domain += [
                ('create_date', '>', date_begin),
                ('create_date', '<=', date_end),
            ]
        # Next, build pager for pagination
        pager_values = portal.portal_pager(
            url=url,
            total=SaleOrder.search_count(domain),
            page=page,
            step=self._items_per_page,
            url_args={'date_begin': date_begin,
                      'date_end': date_end,
                      'sortby': sortby},
        )
        # Then, fetch records with order and pagination
        orders = SaleOrder.search(
            domain,
            order=sort_order,
            limit=self._items_per_page,
            offset=pager_values['offset']
        )
        # Finally, update values for rendering
        values.update({
            'date': date_begin,
            'quotations': orders.sudo() if quotation_page else SaleOrder,
            'orders':    orders.sudo() if not quotation_page else SaleOrder,
            'page_name': 'quote' if quotation_page else 'order',
            'pager':     pager_values,
            'default_url': url,
            'searchbar_sortings': searchbar_sortings,
            'sortby': sortby,
        })
        return values

First, this code extends portal.CustomerPortal. Next, it reads sortby from URL parameters. Then, it merges that parameter into the pager and the search call. Meanwhile, it uses a helper method _get_sale_searchbar_sortings() to define available sorting keys and SQL orders. Finally, it returns the values dict that your template will use.

Step 2 – Define Custom Sort By Options

Next, you create a method to list your portal sorting options. Then, you expose them to the template via controller values.

Sort option method and public route

# File: odoo_discussions/controllers/portal.py

from odoo import http, _
from odoo.http import request

class OdooDiscussions(http.Controller):

    def _get_sale_searchbar_sortings(self):
        return {
            'course_date': {'label': _('Course Date'), 'order': 'course_date desc'},
            'code':        {'label': _('Code'),        'order': 'code'},
            # Add more keys as needed:
            # 'name': {'label': _('Name'), 'order': 'name asc'},
        }

    @http.route('/odoodiscussions/classes', auth='public',
                website=True, type='http')
    def odoodiscussions_classes(self, sortby=None, **kwargs):
        # First, set default if user did not pass ?sortby=
        if sortby is None:
            sortby = 'course_date'
        # Next, get your sorting map
        searchbar_sortings = self._get_sale_searchbar_sortings()
        # Then, find SQL order clause
        sort_order = searchbar_sortings[sortby]['order']
        # Meanwhile, query the course model
        courses = request.env['od_openacademy.course']\
            .search([], order=sort_order)
        # Finally, send values to the portal template
        values = {
            'message': 'Hello Odoo Discussions',
            'courses': courses,
            'page_name': 'course',
            'searchbar_sortings': searchbar_sortings,
            'sortby': sortby,
        }
        return request.render(
            'od_openacademy_website.portal_my_classes', values
        )

First, _get_sale_searchbar_sortings() returns a Python dict. Then, your public route /odoodiscussions/classes reads the sortby parameter and applies it. Meanwhile, you search the od_openacademy.course model with that order. Finally, you render your portal template.

Step 3 – Update XML Template for Sort By Dropdown

Next, you modify your portal template to show a dropdown for sorting. Then, you hook into Odoo’s portal_searchbar and portal_table components.

XML template code

<!-- File: odoo_discussions/views/templates.xml -->
<odoo>
  <template id="portal_my_classes" name="My Classes">
    <t t-call="portal.portal_layout">
      <!-- Activate searchbar and sorting -->
      <t t-set="breadcrumbs_searchbar" t-value="True"/>
      <t t-call="portal.portal_searchbar">
        <t t-set="title">Classes</t>
        <!-- Loop over sort options -->
        <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
          <t t-foreach="searchbar_sortings.items()" t-as="item">
            <li>
              <a t-attf-href="?sortby={{ item[0] }}"
                 t-att-class="{'active': item[0] == sortby}">
                <t t-esc="item[1]['label']"/>
              </a>
            </li>
          </t>
        </ul>
      </t>
      <!-- Render table if courses exist -->
      <t t-if="courses">
        <t t-call="portal.portal_table">
          <thead>
            <tr class="active">
              <th>Course #</th>
              <th class="text-end">Course Name</th>
              <th class="text-end">Course Date</th>
              <th class="text-end">Status</th>
            </tr>
          </thead>
          <tbody>
            <t t-foreach="courses" t-as="course">
              <tr>
                <td>
                  <a t-attf-href="/odoodiscussions/{{ slug(course) }}">
                    <t t-esc="course.code"/>
                  </a>
                </td>
                <td t-esc="course.name"/>
                <td t-esc="course.course_date"/>
                <td t-esc="course.state"/>
              </tr>
            </t>
          </tbody>
        </t>
      </t>
      <!-- Fallback message -->
      <t t-else="">
        <p>No classes found in this order.</p>
      </t>
    </t>
  </template>
</odoo>

First, you call Odoo’s portal layout. Next, you enable the searchbar and loop over searchbar_sortings to show labels. Then, you render the table of courses in the chosen order. Meanwhile, you highlight the active sort choice with CSS.

Step 4 – Test and Debug Your Portal Sort By Feature

First, restart your Odoo server to load updated Python and XML files. Then, clear your browser cache or force-refresh the portal page URL:

http://localhost:8069/odoodiscussions/classes?sortby=code

Meanwhile, verify that:

  1. The dropdown shows “Course Date” and “Code.”
  2. The active option highlights correctly.
  3. Changing the dropdown link reloads the page with a different order.

Common Debugging Steps

  • First, check Odoo logs for Python errors when you hit the route.
  • Next, confirm that your module shows “Installed” under Apps.
  • Then, verify that your XML template ID matches the one in your render call.
  • Finally, inspect the HTML in your browser to ensure the dropdown uses the right URL parameters.

Common Pitfalls and Troubleshooting

First, you might forget to import your new module in __init__.py. Next, you might misalign your XML template IDs. Meanwhile, always check that your Python files have no syntax errors. Finally, confirm that your user has the right access to the custom route by setting auth='public'.

Controller Not Loading?

  • Verify that your controller file is in controllers/portal.py and you imported it in controllers/__init__.py.
  • Meanwhile, ensure you restarted the Odoo service after code changes.

Dropdown Doesn’t Appear?

  • Check if breadcrumbs_searchbar is True.
  • Confirm that your template extends portal.portal_searchbar.
  • Then, inspect the HTML to see if your <ul> block renders.

Best Practices for Odoo Portal Custom Sorting

First, keep your sort option keys consistent. Then, use short labels for clarity. Meanwhile, add translations with _(). Next, document your code so future developers can extend or refactor it. Finally, align your custom routes under a clear namespace (like /odoodiscussions).

Performance Tips

  • Only add sorting on indexed fields (for example, create_date or name) to avoid slow SQL.
  • Meanwhile, limit the number of records per page with portal_pager.
  • Then, cache your sort options in memory if you have many.

UX Considerations

  • Place the sort dropdown near the table header.
  • Use clear active styling (.active class) to show users the current sort.
  • Additionally, include “Default” or “Reset” sort option to return to original order.

Further Resources and Outgoing Link

Moreover, you can deepen your portal customization skills by consulting:

  • Official Odoo Portal Docs: https://www.odoo.com/documentation/17.0/webframework/portal.html
  • Odoo Community Forum for Portal Tips: https://www.odoo.com/forum/help-1
  • Odoo Source Code on GitHub: https://github.com/odoo/odoo

Conclusion and Next Steps

Finally, you have added a fully functional “Sort By” feature to your Odoo 17 portal. First, you overrode the sale order controller. Next, you defined custom sort options. Then, you updated the portal template. Meanwhile, you tested and debugged the feature. Consequently, your users now enjoy tailored portal sorting in Odoo. Now, apply similar steps to add filters, search bars, or more complex actions in your portal. Good luck with your next Odoo customization challenge!


Discover more from teguhteja.id

Subscribe to get the latest posts sent to your email.

Tags:

Leave a Reply

WP Twitter Auto Publish Powered By : XYZScripts.com