Odoo18-Base/addons/website/controllers/model_page.py
2025-01-06 10:57:38 +07:00

115 lines
4.5 KiB
Python

import ast
import werkzeug
from odoo.http import Controller, request, route
from odoo.osv.expression import AND, OR
class ModelPageController(Controller):
pager_step = 20
@route([
"/model/<string:page_name_slugified>",
"/model/<string:page_name_slugified>/page/<int:page_number>",
"/model/<string:page_name_slugified>/<string:record_slug>",
], website=True, auth="public", readonly=True)
def generic_model(self, page_name_slugified=None, page_number=1, record_slug=None, **searches):
if not page_name_slugified:
raise werkzeug.exceptions.NotFound()
website = request.website
website_page_domain = AND([
[("name_slugified", "=", page_name_slugified)],
website.website_domain(),
])
page = request.env["website.controller.page"].search(website_page_domain, limit=1)
if not page or\
(not page.website_published and not request.env.user.has_group('website.group_website_designer')):
raise werkzeug.exceptions.NotFound()
if record_slug is not None:
view = page.sudo().record_view_id
else:
view = page.sudo().view_id
if not view:
raise werkzeug.exceptions.NotFound()
target_model_name = page.sudo().model_id.model
Model = request.env[target_model_name]
if not Model.has_access("read"):
raise werkzeug.exceptions.Forbidden()
rec_domain = ast.literal_eval(page.record_domain or "[]")
domains = [rec_domain]
implements_published_mixin = "website_published" in Model._fields
if implements_published_mixin and not request.env.user.has_group('website.group_website_designer'):
domains.append([("website_published", "=", True)])
if record_slug:
_, res_id = request.env['ir.http']._unslug(record_slug)
record = Model.browse(res_id).filtered_domain(AND(domains))
# We check for slug matching because we are not entirely sure
# that we end up seeing record for the right model
# i.e. in case of a redirect when a "single" page doesn't match the listing
if not record.exists() or record_slug != request.env['ir.http']._slug(record):
raise werkzeug.exceptions.NotFound()
render_context = {
"main_object": page.sudo() if not implements_published_mixin else record, # The template reads some fields that are actually on view
"record": record,
"listing": {
'href': '.',
'name': page.name
}
}
return request.render(view.key, render_context)
layout_mode = request.session.get(f'website_{view.id}_layout_mode')
if not layout_mode:
# use the default layout set for this page
layout_mode = page.default_layout
searches.setdefault("search", "")
searches.setdefault("order", "create_date desc")
def record_to_url(record):
return "/model/%s/%s" % (page.name_slugified, request.env['ir.http']._slug(record))
if searches["search"]:
# _name_search doesn't take offset, we reimplement the logic that builds the name domain here
search_fnames = set(Model._rec_names_search or ([Model._rec_name] if Model._rec_name else []))
if "seo_name" in Model._fields:
search_fnames.add("seo_name")
if search_fnames:
name_domain = OR([[(name_field, "ilike", searches["search"])] for name_field in search_fnames])
domains.append(name_domain)
search_count = Model.search_count(AND(domains))
pager = website.pager(
url=f"/model/{page.name_slugified}",
url_args=searches,
total=search_count,
page=page_number,
step=self.pager_step,
scope=5,
)
records = Model.search(AND(domains), limit=self.pager_step, offset=self.pager_step * (page_number - 1), order=searches["order"])
render_context = {
"order_by": searches["order"],
"search": searches["search"],
"search_count": search_count,
"pager": pager,
"records": records,
"record_to_url": record_to_url,
"layout_mode": layout_mode,
"view_id": view.id,
"main_object": page.sudo(), # The template reads some fields that are actually on view
}
return request.render(view.key, render_context)