[IMP] website_forum: optimize query

Optimize queries
Fix multi-forum / mutliwebsite in child count
Use stored field when possible
Avoid forum count on each request (rarely updated)

closes odoo/odoo#52539

Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
Odoo's Mergebot
2020-06-08 14:53:07 +02:00
committed by GitHub
5 changed files with 33 additions and 18 deletions
+1 -1
View File
@@ -654,7 +654,7 @@ class Website(models.Model):
@api.model
def is_public_user(self):
return request.env.user.id == request.website.user_id.id
return request.env.user.id == request.website._get_cached('user_id')
@api.model
def viewref(self, view_id, raise_if_not_found=True):
+5 -3
View File
@@ -235,8 +235,6 @@ class WebsiteForum(WebsiteProfile):
if question.state == 'pending' and user.karma < forum.karma_post and question.create_uid != user:
raise werkzeug.exceptions.NotFound()
# increment view counter
question.sudo().set_viewed()
if question.parent_id:
redirect_url = "/forum/%s/question/%s" % (slug(forum), slug(question.parent_id))
return werkzeug.utils.redirect(redirect_url, 301)
@@ -245,13 +243,17 @@ class WebsiteForum(WebsiteProfile):
values.update({
'main_object': question,
'question': question,
'can_bump': (question.forum_id.allow_bump and not question.child_ids and (datetime.today() - question.write_date).days > 9),
'can_bump': (question.forum_id.allow_bump and not question.child_count and (datetime.today() - question.write_date).days > 9),
'header': {'question_data': True},
'filters': filters,
'reversed': reversed,
})
if (request.httprequest.referrer or "").startswith(request.httprequest.url_root):
values['back_button_url'] = request.httprequest.referrer
# increment view counter
question.sudo().set_viewed()
return request.render("website_forum.post_description_full", values)
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/toggle_favourite', type='json', auth="user", methods=['POST'], website=True)
+18 -4
View File
@@ -177,7 +177,7 @@ class Forum(models.Model):
@api.model
def create(self, values):
res = super(Forum, self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)).create(values)
res._set_default_faq()
res._set_default_faq() # will trigger a write and call update_website_count
return res
def write(self, vals):
@@ -199,8 +199,15 @@ class Forum(models.Model):
if 'active' in vals:
# archiving/unarchiving a forum does it on its posts, too
self.env['forum.post'].with_context(active_test=False).search([('forum_id', 'in', self.ids)]).write({'active': vals['active']})
if 'active' in vals or 'website_id' in vals:
self._update_website_count()
return res
def unlink(self):
self._update_website_count()
return super(Forum, self).unlink()
@api.model
def _tag_to_write_vals(self, tags=''):
Tag = self.env['forum.tag']
@@ -238,6 +245,12 @@ class Forum(models.Model):
'url': self._compute_website_url(),
}
@api.model
def _update_website_count(self):
for website in self.env['website'].sudo().search([]):
website.forums_count = self.env['forum.forum'].sudo().search_count(website.website_domain())
class Post(models.Model):
_name = 'forum.post'
@@ -281,7 +294,7 @@ class Post(models.Model):
is_correct = fields.Boolean('Correct', help='Correct answer or answer accepted')
parent_id = fields.Many2one('forum.post', string='Question', ondelete='cascade', readonly=True, index=True)
self_reply = fields.Boolean('Reply to own question', compute='_is_self_reply', store=True)
child_ids = fields.One2many('forum.post', 'parent_id', string='Post Answers')
child_ids = fields.One2many('forum.post', 'parent_id', string='Post Answers', domain=lambda self: [('forum_id', '=', self.forum_id.id)])
child_count = fields.Integer('Answers', compute='_get_child_count', store=True)
uid_has_answered = fields.Boolean('Has Answered', compute='_get_uid_has_answered')
has_validated_answer = fields.Boolean('Is answered', compute='_get_has_validated_answer', store=True)
@@ -401,7 +414,7 @@ class Post(models.Model):
def _get_uid_has_answered(self):
for post in self:
post.uid_has_answered = any(answer.create_uid.id == post._uid for answer in post.child_ids)
post.uid_has_answered = post._uid in post.child_ids.create_uid.ids
@api.depends('child_ids.is_correct')
def _get_has_validated_answer(self):
@@ -838,7 +851,8 @@ class Post(models.Model):
return result
def set_viewed(self):
self._cr.execute("""UPDATE forum_post SET views = views+1 WHERE id IN %s""", (self._ids,))
self.ensure_one()
self._cr.execute("""UPDATE forum_post SET views = views+1 WHERE views = %s and id = %s""", (self.views, self.id,))
return True
def get_access_action(self, access_uid=None):
+5 -6
View File
@@ -1,19 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, _
from odoo import models, fields, api, _
from odoo.addons.http_routing.models.ir_http import url_for
class Website(models.Model):
_inherit = 'website'
def _compute_field_forums_count(self):
Forum = self.env['forum.forum']
for website in self:
website.forums_count = Forum.search_count(website.website_domain())
@api.model
def get_default_forum_count(self):
self.forums_count = self.env['forum.forum'].search_count(self.website_domain())
forums_count = fields.Integer(compute=_compute_field_forums_count)
forums_count = fields.Integer(readonly=True, default=get_default_forum_count)
def get_suggested_controllers(self):
suggested_controllers = super(Website, self).get_suggested_controllers()
+4 -4
View File
@@ -288,7 +288,7 @@
</div>
<div>
<span class="mx-1 d-none d-sm-inline">&amp;nbsp;|</span>
<a t-if="len(question.child_ids)&gt;0" class="font-weight-bold" t-attf-href="/forum/#{ slug(question.forum_id) }/question/#{ slug(question) }">
<a t-if="question.child_count" class="font-weight-bold" t-attf-href="/forum/#{ slug(question.forum_id) }/question/#{ slug(question) }">
<t t-esc="question.child_count"/>
<t t-if="question.child_count == 1">Answer</t>
<t t-else="">Answers</t>
@@ -1181,10 +1181,10 @@
<t t-set="_collapse_uid" t-value="_question_comment_collapse_uid"/>
</t>
<section t-if="question.child_ids" t-attf-class="#{question.website_message_ids and 'mt-5' or 'mt-4'}">
<section t-if="question.child_count" t-attf-class="#{question.website_message_ids and 'mt-5' or 'mt-4'}">
<h5>
<t t-esc="len(question.child_ids)"/>
<t t-if="len(question.child_ids) == 1">Answer</t>
<t t-esc="question.child_count"/>
<t t-if="question.child_count == 1">Answer</t>
<t t-else="">Answers</t>
</h5>