зеркало из https://github.com/mozilla/kitsune.git
Stop Answer.get_absolute_url() from making any DB queries.
This commit is contained in:
Родитель
8968d161c0
Коммит
9930bf85fb
|
@ -41,6 +41,20 @@
|
|||
"num_answers": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 4,
|
||||
"model": "questions.question",
|
||||
"fields": {
|
||||
"status": 1,
|
||||
"updated": "2010-06-17 19:47:34",
|
||||
"creator": 47963,
|
||||
"is_locked": false,
|
||||
"created": "2010-06-17 19:47:34",
|
||||
"content": "It's a marvellous night for an audio lolrus foo.",
|
||||
"title": "lolrus too?",
|
||||
"num_answers": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "questions.questionmetadata",
|
||||
|
@ -125,5 +139,29 @@
|
|||
"content": "An answer & stuff.",
|
||||
"upvotes": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "questions.answer",
|
||||
"fields": {
|
||||
"updated": "2010-06-23 19:48:00",
|
||||
"created": "2010-06-23 19:48:00",
|
||||
"creator": 118533,
|
||||
"question": 4,
|
||||
"content": "An answer & stuff, too.",
|
||||
"upvotes": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "questions.answer",
|
||||
"fields": {
|
||||
"updated": "2010-06-24 19:48:00",
|
||||
"created": "2010-06-24 19:48:00",
|
||||
"creator": 118533,
|
||||
"question": 4,
|
||||
"content": "An answer & stuff, too.",
|
||||
"upvotes": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -21,7 +21,8 @@ from sumo.helpers import urlparams
|
|||
import questions as constants
|
||||
from questions.tags import add_existing_tag
|
||||
from .question_config import products
|
||||
from .tasks import update_question_votes, build_answer_notification
|
||||
from .tasks import (update_question_votes, build_answer_notification,
|
||||
update_answer_pages)
|
||||
from upload.models import ImageAttachment
|
||||
|
||||
|
||||
|
@ -252,6 +253,7 @@ class Answer(ModelBase):
|
|||
updated_by = models.ForeignKey(User, null=True,
|
||||
related_name='answers_updated')
|
||||
upvotes = models.IntegerField(default=0, db_index=True)
|
||||
page = models.IntegerField(default=1)
|
||||
|
||||
images = generic.GenericRelation(ImageAttachment)
|
||||
flags = generic.GenericRelation(FlaggedObject)
|
||||
|
@ -274,7 +276,10 @@ class Answer(ModelBase):
|
|||
|
||||
new = self.id is None
|
||||
|
||||
if not new:
|
||||
if new:
|
||||
page = self.question.num_answers / constants.ANSWERS_PER_PAGE + 1
|
||||
self.page = page
|
||||
else:
|
||||
self.updated = datetime.now()
|
||||
|
||||
super(Answer, self).save(*args, **kwargs)
|
||||
|
@ -305,21 +310,15 @@ class Answer(ModelBase):
|
|||
|
||||
super(Answer, self).delete(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def page(self):
|
||||
"""Get the page of the question on which this answer is found."""
|
||||
t = self.question
|
||||
earlier = t.answers.filter(created__lte=self.created).count() - 1
|
||||
if earlier < 1:
|
||||
return 1
|
||||
return earlier / constants.ANSWERS_PER_PAGE + 1
|
||||
update_answer_pages.delay(question)
|
||||
|
||||
def get_absolute_url(self):
|
||||
query = {}
|
||||
if self.page > 1:
|
||||
query = {'page': self.page}
|
||||
|
||||
url = self.question.get_absolute_url()
|
||||
url = reverse('questions.answers',
|
||||
kwargs={'question_id': self.question_id})
|
||||
return urlparams(url, hash='answer-%s' % self.id, **query)
|
||||
|
||||
@property
|
||||
|
|
|
@ -12,6 +12,7 @@ from celery.decorators import task
|
|||
from tower import ugettext as _
|
||||
|
||||
from notifications.tasks import send_notification
|
||||
from questions import ANSWERS_PER_PAGE
|
||||
from sumo.urlresolvers import reverse
|
||||
|
||||
|
||||
|
@ -92,3 +93,15 @@ def send_confirmation_email(question):
|
|||
'confirm_url': url,
|
||||
'host': Site.objects.get_current().domain}))
|
||||
send_mail(subject, content, from_address, [question.creator.email])
|
||||
|
||||
|
||||
@task(rate_limit='4/m')
|
||||
def update_answer_pages(question):
|
||||
log.debug('Recalculating answer page numbers for question %s: %s' %
|
||||
(question.pk, question.title))
|
||||
|
||||
i = 0
|
||||
for answer in question.answers.using('default').order_by('created').all():
|
||||
answer.page = i / ANSWERS_PER_PAGE + 1
|
||||
answer.save(no_update=True, no_notify=True)
|
||||
i += 1
|
||||
|
|
|
@ -10,6 +10,7 @@ from flagit.models import FlaggedObject
|
|||
from questions.models import (Question, QuestionMetaData, Answer,
|
||||
_tenths_version)
|
||||
from questions.tags import add_existing_tag
|
||||
from questions.tasks import update_answer_pages
|
||||
from questions.tests import TestCaseBase, TaggingTestCaseBase, tags_eq
|
||||
from questions.question_config import products
|
||||
|
||||
|
@ -105,13 +106,32 @@ class TestAnswer(TestCaseBase):
|
|||
question = Question.objects.get(pk=question.id)
|
||||
eq_(question.solution, None)
|
||||
|
||||
def test_update_page_task(self):
|
||||
answer = Answer.objects.get(pk=1)
|
||||
answer.page = 4
|
||||
answer.save()
|
||||
answer = Answer.objects.get(pk=1)
|
||||
assert answer.page == 4
|
||||
update_answer_pages(answer.question)
|
||||
a = Answer.objects.get(pk=1)
|
||||
assert a.page == 1
|
||||
|
||||
def test_delete_updates_pages(self):
|
||||
a1 = Answer.objects.get(pk=2)
|
||||
a2 = Answer.objects.get(pk=3)
|
||||
a1.page = 7
|
||||
a1.save()
|
||||
a2.delete()
|
||||
a3 = Answer.objects.filter(question=a1.question)[0]
|
||||
assert a3.page == 1, "Page was %s" % a3.page
|
||||
|
||||
def test_creator_num_posts(self):
|
||||
"""Test retrieval of post count for creator of a particular answer"""
|
||||
question = Question.objects.all()[0]
|
||||
answer = Answer(question=question, creator_id=47963,
|
||||
content="Test Answer")
|
||||
|
||||
eq_(answer.creator_num_posts, 2)
|
||||
eq_(answer.creator_num_posts, 4)
|
||||
|
||||
def test_creator_num_answers(self):
|
||||
"""Test retrieval of answer count for creator of a particular answer"""
|
||||
|
|
|
@ -779,7 +779,7 @@ class QuestionsTemplateTestCase(TestCaseBase):
|
|||
response = self.client.get(url_)
|
||||
doc = pq(response.content)
|
||||
eq_('active', doc('div#filter ul li')[4].attrib['class'])
|
||||
eq_(3, len(doc('ol.questions li')))
|
||||
eq_(4, len(doc('ol.questions li')))
|
||||
|
||||
# solve one question then verify that it doesn't show up
|
||||
answer = Answer.objects.all()[0]
|
||||
|
@ -787,7 +787,7 @@ class QuestionsTemplateTestCase(TestCaseBase):
|
|||
answer.question.save()
|
||||
response = self.client.get(url_)
|
||||
doc = pq(response.content)
|
||||
eq_(2, len(doc('ol.questions li')))
|
||||
eq_(3, len(doc('ol.questions li')))
|
||||
eq_(0, len(doc('ol.questions li#question-%s' % answer.question.id)))
|
||||
|
||||
def _my_contributions_test_helper(self, username, expected_qty):
|
||||
|
@ -801,10 +801,10 @@ class QuestionsTemplateTestCase(TestCaseBase):
|
|||
|
||||
def test_my_contributions_filter(self):
|
||||
# jsocol should have 2 questions in his contributions
|
||||
self._my_contributions_test_helper('jsocol', 2)
|
||||
self._my_contributions_test_helper('jsocol', 3)
|
||||
|
||||
# pcraciunoiu should have 2 questions in his contributions'
|
||||
self._my_contributions_test_helper('pcraciunoiu', 2)
|
||||
self._my_contributions_test_helper('pcraciunoiu', 3)
|
||||
|
||||
# rrosario should have 0 questions in his contributions
|
||||
self._my_contributions_test_helper('rrosario', 0)
|
||||
|
|
|
@ -236,7 +236,7 @@ class SearchTest(SphinxTestCase):
|
|||
qs = {'a': 1, 'format': 'json', 'page': 'invalid'}
|
||||
response = self.client.get(reverse('search'), qs)
|
||||
eq_(200, response.status_code)
|
||||
eq_(4, json.loads(response.content)['total'])
|
||||
eq_(5, json.loads(response.content)['total'])
|
||||
|
||||
def test_search_metrics(self):
|
||||
"""Ensure that query strings are added to search results"""
|
||||
|
@ -266,7 +266,7 @@ class SearchTest(SphinxTestCase):
|
|||
def test_category_invalid(self):
|
||||
qs = {'a': 1, 'w': 3, 'format': 'json', 'category': 'invalid'}
|
||||
response = self.client.get(reverse('search'), qs)
|
||||
eq_(4, json.loads(response.content)['total'])
|
||||
eq_(5, json.loads(response.content)['total'])
|
||||
|
||||
def test_no_filter(self):
|
||||
"""Test searching with no filters."""
|
||||
|
@ -363,7 +363,7 @@ class SearchTest(SphinxTestCase):
|
|||
qs = {'a': 1, 'w': 2, 'format': 'json',
|
||||
'sortby': 1, 'updated_date': '06/20/2010'}
|
||||
updated_vals = (
|
||||
(1, '/3'),
|
||||
(1, '/4'),
|
||||
(2, '/2'),
|
||||
)
|
||||
|
||||
|
@ -380,7 +380,7 @@ class SearchTest(SphinxTestCase):
|
|||
qs = {'a': 1, 'w': 2, 'format': 'json',
|
||||
'updated': 1, 'updated_date': 'invalid'}
|
||||
response = self.client.get(reverse('search'), qs)
|
||||
eq_(3, json.loads(response.content)['total'])
|
||||
eq_(4, json.loads(response.content)['total'])
|
||||
|
||||
def test_updated_nonexistent(self):
|
||||
"""updated is set while updated_date is left out of the query."""
|
||||
|
@ -404,7 +404,7 @@ class SearchTest(SphinxTestCase):
|
|||
author_vals = (
|
||||
('DoesNotExist', 0),
|
||||
('jsocol', 2),
|
||||
('pcraciunoiu', 1),
|
||||
('pcraciunoiu', 2),
|
||||
)
|
||||
|
||||
for author, total in author_vals:
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
-- Model: Answer
|
||||
ALTER TABLE `questions_answer`
|
||||
ADD `page` integer default 1;
|
||||
|
||||
-- Set page numbers for existing answers.
|
||||
UPDATE questions_answer a
|
||||
SET
|
||||
page = (
|
||||
SELECT COUNT(*)
|
||||
FROM (
|
||||
SELECT id, question_id, created
|
||||
FROM questions_answer) b
|
||||
WHERE b.question_id = a.question_id AND b.created < a.created
|
||||
) / 20 + 1;
|
Загрузка…
Ссылка в новой задаче