-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: replace faulty migration for calc answers with a command
The migration `0047_recalculate_calc_answers` was error prone and took a long time to execute. This commit replaces it with a management command that is more optimized and stable. Still this operation will take some time to finish.
- Loading branch information
1 parent
d1000be
commit 4a3e85c
Showing
4 changed files
with
108 additions
and
135 deletions.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
caluma/caluma_form/management/commands/recalculate_calc_answers.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from django.core.management.base import BaseCommand | ||
|
||
from caluma.caluma_form.models import Answer, Question | ||
from caluma.caluma_form.signals import _update_or_create_calc_answer | ||
|
||
|
||
class Command(BaseCommand): | ||
""" | ||
Recalculate calculated answers containing values from TableAnswers. | ||
Due to a bug, answers to calculated questions were wrong, if they contained values | ||
from table rows. This command recalculates all of them. | ||
""" | ||
|
||
help = "Recalculate calculated answers containing values from TableAnswers." | ||
|
||
def handle(self, *args, **options): | ||
affected_questions = ( | ||
Question.objects.filter(type="table") | ||
.exclude(calc_dependents=[]) | ||
.values_list("calc_dependents", flat=True) | ||
) | ||
|
||
affected_questions_clean = set( | ||
[slug for entry in affected_questions for slug in entry] | ||
) | ||
|
||
calc_answers = Answer.objects.filter( | ||
question__type="calculated_float", | ||
document__isnull=False, | ||
question__slug__in=affected_questions_clean, | ||
) | ||
|
||
for answer in calc_answers.iterator(): | ||
_update_or_create_calc_answer(answer.question, answer.document) |
54 changes: 0 additions & 54 deletions
54
caluma/caluma_form/migrations/0047_recalculate_calc_answers.py
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
caluma/caluma_form/tests/test_recalculate_calc_answers_command.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import os | ||
|
||
from django.core.management import call_command | ||
|
||
from caluma.caluma_form.api import save_answer, save_document | ||
from caluma.caluma_form.models import Question | ||
|
||
|
||
def test_recalculate_calc_answers( | ||
form_factory, | ||
question_factory, | ||
form_question_factory, | ||
): | ||
# set up form structure | ||
main_form_question = form_question_factory( | ||
question__type=Question.TYPE_INTEGER, question__slug="dep1_main" | ||
) | ||
main_form = main_form_question.form | ||
dep1_main = main_form_question.question | ||
|
||
row_form = form_factory(slug="row_form") | ||
table_question = question_factory( | ||
type="table", | ||
slug="table_question", | ||
row_form=row_form, | ||
is_required="true", | ||
is_hidden="false", | ||
) | ||
form_question_factory(form=main_form, question=table_question) | ||
|
||
row_form_question = form_question_factory( | ||
form=row_form, | ||
question__type=Question.TYPE_INTEGER, | ||
question__slug="dep2_row", | ||
question__is_required=True, | ||
) | ||
dep2_row = row_form_question.question | ||
|
||
form_question_factory( | ||
form=main_form, | ||
question__slug="calc_question", | ||
question__type=Question.TYPE_CALCULATED_FLOAT, | ||
question__calc_expression=( | ||
f'"dep1_main"|answer(0) + "{table_question.slug}"|answer([])|mapby("dep2_row")|sum' | ||
), | ||
) | ||
|
||
# assert calc_dependents | ||
dep1_main.refresh_from_db() | ||
dep2_row.refresh_from_db() | ||
assert dep1_main.calc_dependents == ["calc_question"] | ||
assert dep2_row.calc_dependents == ["calc_question"] | ||
|
||
# set up document and answers | ||
main_doc = save_document(form=main_form) | ||
save_answer(question=dep1_main, value=10, document=main_doc) | ||
row_doc = save_document(form=row_form) | ||
save_answer(question=dep2_row, value=13, document=row_doc) | ||
save_answer(table_question, document=main_doc, value=[str(row_doc.pk)]) | ||
calc_answer = main_doc.answers.get(question_id="calc_question") | ||
|
||
# assert calc bug is fixed | ||
assert calc_answer.value == 23 | ||
|
||
# set calc_answer.value to 10, like it would have been without the fix | ||
calc_answer.value = 10 | ||
calc_answer.save() | ||
|
||
call_command("recalculate_calc_answers", stderr=open(os.devnull, "w")) | ||
|
||
# assert correct calc_value after migration | ||
calc_answer.refresh_from_db() | ||
assert calc_answer.value == 23 |