Stop Answer.get_absolute_url() from making any DB queries.

This commit is contained in:
James Socol 2010-09-01 11:29:00 -04:00
Родитель 8968d161c0
Коммит 9930bf85fb
7 изменённых файлов: 105 добавлений и 21 удалений

Просмотреть файл

@ -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;