In Odoo, a generic controller typically refers to a controller class that provides a generic set of functionalities or behaviors that can be reused across multiple models or modules. Controllers in Odoo are part of the MVC (Model-View-Controller) architecture and are responsible for handling web requests.
A generic controller can be designed to perform common actions, such as creating, updating, or deleting records, and it can be applied to various models without the need to duplicate code. This promotes code reusability and maintainability.
So, let's create a generic controller to create a record in any model on submitting the website form.
For that lets create a website menu in the data folder of the module.
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="website_partner_menu" model="website.menu">
<field name="name">Partner</field>
<field name="url">/partner</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence" type="int">90</field>
</record>
</odoo>
We need to define the controller function
from odoo.http import Controller, route, request
class Partner(Controller):
@route(route=['/partner’], type='http', auth='public',
website=True)
def partner(self):
partners = request.env['res.partner'].sudo().search([])
users = request.env['res.users'].sudo().search([])
sales_team = request.env['crm.team'].sudo().search([])
return request.render('generic_controller.generic_controller_form',
{'partners': partners,
'users': users,
'sales_team':sales_team})
First, we need to set up the template for the website form, including input fields and specifying an action to create a lead in the crm.lead model.
<template id="generic_controller_form" name="Generic Controller">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty">
<section class="s_website_form" data-vcss="001"
data-snippet="s_website_form">
<div class="container">
<section
class="s_text_block pt40 pb40 o_colored_level "
data-snippet="s_text_block">
<div class="container s_allow_columns">
<div class="row">
<div class="col-lg-8 mt-4 mt-lg-0">
<section class="s_website_form"
data-vcss="001"
data-snippet="s_website_form">
<div class="container">
<form action="/generic_controller"
method="post"
enctype="multipart/form-data"
class="o_mark_required"
data-mark="*"
data-model_name=""
data-success-page="">
<input type="hidden"
name="csrf_token"
t-att-value="request.csrf_token()"/>
<input type="hidden"
name="model"
value="crm.lead"/>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_custom s_website_form_required"
data-type="char"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="name">
<span class="s_website_form_label_content">
Opportunity
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input id="name"
type="text"
class="form-control s_website_form_input"
name="name"
required=""
data-fill-with="name"/>
</div>
</div>
</div>
<div class="form-group col-12 s_website_form_field s_website_form_custom"
data-type="char"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="partner_id">
<span class="s_website_form_label_content">
Customer
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select name="partner_id"
t-attf-class="form-control s_website_form_input required=">
<t t-foreach="partners or []"
t-as="partner">
<option t-att-value="partner.id">
<t t-esc="partner.name"/>
</option>
</t>
</select>
</div>
</div>
</div>
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="email"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="contact3">
<span class="s_website_form_label_content">
Email
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input id="email"
type="email"
class="form-control s_website_form_input"
name="email_from"
required=""
data-fill-with="email"/>
</div>
</div>
</div>
<div class="form-group col-12 s_website_form_field s_website_form_custom"
data-type="char"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="phone">
<span class="s_website_form_label_content">
Phone
</span>
</label>
<div class="col-sm">
<input id="phone"
type="tel"
class="form-control s_website_form_input"
name="phone"
data-fill-with="phone"/>
</div>
</div>
</div>
<div class="form-group col-12 s_website_form_field
s_website_form_custom"
data-type="char"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto
s_website_form_label"
style="width: 200px"
for="user_id">
<span class="s_website_form_label_content">
Salesperson
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select name="user_id"
t-attf-class="form-control s_website_form_input"
required="1">
<t t-foreach="users or []"
t-as="user">
<option t-att-value="user.id">
<t t-esc="user.name"/>
</option>
</t>
</select>
</div>
</div>
</div>
<div class="form-group col-12 s_website_form_field s_website_form_custom"
data-type="char"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="team_id">
<span class="s_website_form_label_content">
Sales
Team
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select name="team_id"
t-attf-class="form-control s_website_form_input"
required="1">
<t t-foreach="sales_team or []"
t-as="team">
<option t-att-value="team.id">
<t t-esc="team.name"/>
</option>
</t>
</select>
</div>
</div>
</div>
<div class="form-group col-12 s_website_form_submit"
data-name="Submit Button">
<div style="width: 200px;"
class="s_website_form_label"/>
<button type="submit"
class="btn btn-primary">
Submit
</button>
</div>
</div>
</form>
</div>
</section>
</div>
</div>
</div>
</section>
</div>
</section>
</div>
</t>
</template>
When crafting the form template, it's essential to include the model name within the markup, like so: <input type="hidden" name="model" value="crm.lead"/>. Here, within the value attribute, we must specify the model name. Additionally, in the template definition, we can align the field names with those of the form fields themselves.
Following the form setup, we proceed to establish the generic controller to execute after form submission.
@route('/generic_controller', methods=['POST'], auth="public", website=True)
def menu_generic_controller_request_submit(self, **kw):
values = {}
fields = request.env['ir.model'].sudo().search([('model', '=', kw.get('model'))]).field_id
for key, val in kw.items():
field_id = fields.sudo().filtered(lambda r: r.sudo().name == key).sudo()
if not field_id:
continue
if field_id.ttype == 'many2one':
val = int(val) if val else 0
values.update({
key: val
})
record = request.env[kw.get('model')].sudo().create(values)
return request.render("website_form.generic_controller_form",{})
This controller function retrieves the submitted form data and creates a record in the specified model based on the provided input. It dynamically identifies the fields associated with the model and populates them with the corresponding values from the form submission.
In conclusion, by implementing a generic controller in the Odoo 17 Website, we enhance the flexibility and efficiency of form submissions. This approach streamlines the process of record creation across various models, contributing to a more cohesive and scalable web application.