In Odoo, normally, website forms allow users to enter data, and on submission, corresponding controllers will be called, and the records will be created in the model specified in the controller.
In this blog, we will create a generic controller that can be used to create records in any model upon submission of the form.
1. First, we must create a website form with the input fields.
<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="sale.order"/>
<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="1">
<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>
While creating the form template, we need to pass the model name as <input type="hidden" name="model" value="sale.order"/> where in value, we need to specify the model name. Also, in template definition, we can specify the field name as the name of the form fields.
2. Next, we can define a generic controller, which will be called after submitting the form
@http.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
http.request.render("generic_controller_app.generic_controller_form", {})
In conclusion, the provided code demonstrates the creation of a generic controller in Odoo to handle form submissions from the website. The generic controller allows the dynamic creation of records in any specified model based on the form data submitted. This approach enhances reusability and simplifies creating new forms for different models on the Odoo website. If you want to know more about the Odoo 16 website module, refer to our previous blogs.