Lots of improvemnets
This commit is contained in:
+7
-1
@@ -150,6 +150,7 @@ class AnatomyQuestionForm(ModelForm):
|
|||||||
"region",
|
"region",
|
||||||
"modality",
|
"modality",
|
||||||
"structure",
|
"structure",
|
||||||
|
"feedback",
|
||||||
"examination",
|
"examination",
|
||||||
"body_part",
|
"body_part",
|
||||||
"description",
|
"description",
|
||||||
@@ -158,9 +159,14 @@ class AnatomyQuestionForm(ModelForm):
|
|||||||
|
|
||||||
widgets = {
|
widgets = {
|
||||||
"structure": autocomplete.ModelSelect2(url="atlas:structure-autocomplete"),
|
"structure": autocomplete.ModelSelect2(url="atlas:structure-autocomplete"),
|
||||||
"answer_help": TinyMCE(attrs={"cols": 80, "rows": 10}),
|
"answer_help": TinyMCE(attrs={"cols": 80, "rows": 5}),
|
||||||
|
"feedback": TinyMCE(attrs={"cols": 80, "rows": 5}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AnatomyQuestionAnswerForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = AnatomyQuestion
|
||||||
|
fields = []
|
||||||
|
|
||||||
AnswerFormSet = inlineformset_factory(
|
AnswerFormSet = inlineformset_factory(
|
||||||
AnatomyQuestion,
|
AnatomyQuestion,
|
||||||
|
|||||||
@@ -451,6 +451,18 @@ class Exam(ExamBase):
|
|||||||
|
|
||||||
return exam_json
|
return exam_json
|
||||||
|
|
||||||
|
def get_question_cid_user_answer(self, question_index, cid):
|
||||||
|
question = self.get_question_by_index(question_index)
|
||||||
|
answer = UserAnswer.objects.filter(question=question, cid=cid, exam=self)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
def get_question_user_user_answer(self, question_index, user):
|
||||||
|
print(user)
|
||||||
|
question = self.get_question_by_index(question_index)
|
||||||
|
answer = UserAnswer.objects.filter(question=question, user=user.pk, exam=self)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class UserAnswer(UserAnswerBase):
|
class UserAnswer(UserAnswerBase):
|
||||||
|
|||||||
@@ -26,17 +26,10 @@
|
|||||||
|
|
||||||
document.addEventListener('drop', function (e) { e.preventDefault(); }, false);
|
document.addEventListener('drop', function (e) { e.preventDefault(); }, false);
|
||||||
|
|
||||||
function add_input_form() {
|
|
||||||
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
|
||||||
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
|
|
||||||
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#add_examination").appendTo($("label[for='id_examination']"));
|
$("#add_examination").appendTo($("label[for='id_examination']"));
|
||||||
$("#add_body_part").appendTo($("label[for='id_body_part']"));
|
$("#add_body_part").appendTo($("label[for='id_body_part']"));
|
||||||
$("#add_structure").appendTo($("label[for='id_structure']"));
|
|
||||||
|
|
||||||
|
|
||||||
dropContainer = document.getElementById("drop-container");
|
dropContainer = document.getElementById("drop-container");
|
||||||
@@ -221,15 +214,18 @@
|
|||||||
{{ form.media }}
|
{{ form.media }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Submit Question</h2>
|
|
||||||
|
{% if object %}
|
||||||
|
{% include 'anatomy/question_link_header.html' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h2>{{object|yesno:"Update,Create"}} Question</h2>
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="anatomyquestion-form">
|
<form action="" method="post" enctype="multipart/form-data" id="anatomyquestion-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<a href="/anatomy/examination/create" id="add_examination" class="add-popup"
|
<a href="/anatomy/examination/create" id="add_examination" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
|
||||||
<a href="/anatomy/body_part/create" id="add_body_part" class="add-popup"
|
<a href="/anatomy/body_part/create" id="add_body_part" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
|
||||||
<a href="/anatomy/structure/create" id="add_structure" class="add-popup" onclick="return showAddPopup(this);"><img
|
|
||||||
src="{% static '/img/icon-addlink.svg' %}"></a>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
{{ form.as_table }}
|
{{ form.as_table }}
|
||||||
@@ -237,24 +233,6 @@
|
|||||||
<div id="drop-container" class="drop-target">Drop image here
|
<div id="drop-container" class="drop-target">Drop image here
|
||||||
<div id="drop-filenames"></div>
|
<div id="drop-filenames"></div>
|
||||||
</div>
|
</div>
|
||||||
<h3>Answers:</h3>
|
|
||||||
<input type="button" value="Add More Answers" id="add_more">
|
|
||||||
<div id="form_set">
|
|
||||||
{% for form in answer_formset %}
|
|
||||||
<ul class="no-error answer-formset">
|
|
||||||
{{form.non_field_errors}}
|
|
||||||
{{form.errors}}
|
|
||||||
{{ form.as_ul }}
|
|
||||||
</ul>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{{ answer_formset.management_form }}
|
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
<input type="submit" class="submit-button" value="Submit and Clone" name="submit-clone">
|
|
||||||
</form>
|
</form>
|
||||||
<div id="empty_form" style="display:none">
|
|
||||||
<ul class='no_error answer-formset'>
|
|
||||||
{{ answer_formset.empty_form.as_ul }}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{% extends "anatomy/base.html" %}
|
||||||
|
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function add_input_form() {
|
||||||
|
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
||||||
|
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
|
||||||
|
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('#add_more').click(() => {
|
||||||
|
add_input_form()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ form.media }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if object %}
|
||||||
|
{% include 'anatomy/question_link_header.html' %}
|
||||||
|
{% endif %}
|
||||||
|
<h2>Question Answers</h2>
|
||||||
|
This page can be used to add and modify answers associated with a question. Answers in here will be used for automarking submitted answers so it is best not to remove. Updating an answer here will not automatically update a submitted answers (scores cache would need to be refreshed)
|
||||||
|
<form action="" method="post" enctype="multipart/form-data" id="anatomyquestion-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h3>Answers:</h3>
|
||||||
|
<div id="form_set">
|
||||||
|
{% for form in answer_formset %}
|
||||||
|
<ul class="no-error answer-formset">
|
||||||
|
{{form.non_field_errors}}
|
||||||
|
{{form.errors}}
|
||||||
|
{{ form.as_ul }}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{{ answer_formset.management_form }}
|
||||||
|
<input type="button" value="Add More Answers" id="add_more">
|
||||||
|
<p>
|
||||||
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<div id="empty_form" style="display:none">
|
||||||
|
<ul class='no_error answer-formset'>
|
||||||
|
{{ answer_formset.empty_form.as_ul }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -10,7 +10,12 @@
|
|||||||
{% endfor %} {% endcomment %}
|
{% endfor %} {% endcomment %}
|
||||||
{% for cid in cids %}
|
{% for cid in cids %}
|
||||||
{% with by_question|get_item:question|get_item:cid as ans_score %}
|
{% with by_question|get_item:question|get_item:cid as ans_score %}
|
||||||
<td class="anatomy-ans user-answer-score-{{ans_score.1}}" title="answer score: {{ans_score.1}}">{{ans_score.0}}</td>
|
<td class="anatomy-ans user-answer-score-{{ans_score.1}}"
|
||||||
|
title="answer score: {{ans_score.1}}"
|
||||||
|
data-examquestionindex={{forloop.parentloop.counter0}}
|
||||||
|
data-cid={{cid}}
|
||||||
|
>{{ans_score.0}}<a class="show-on-hover" href="{% url 'anatomy:exam_question_user_answer' exam.pk forloop.parentloop.counter0 cid|slice:':1' cid|slice:'2:' %}"><i class="bi bi-pen"></i>
|
||||||
|
</a></td>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,40 +1,15 @@
|
|||||||
{% extends 'anatomy/base.html' %}
|
{% extends 'anatomy/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<!-- testing -->
|
<!-- testing -->
|
||||||
<!--<div id="dicom-image" data-url="http://localhost:8000/static/abdoct.jpg"
|
<!--<div id="dicom-image" data-url="http://localhost:8000/static/abdoct.jpg"
|
||||||
data-annotations='{{question.image_annotations}}' data-edit_annotation=true></div>-->
|
data-annotations='{{question.image_annotations}}' data-edit_annotation=true></div>-->
|
||||||
<div class="floating-header">
|
{% include 'anatomy/question_link_header.html' %}
|
||||||
<a href="{% url 'anatomy:anatomy_question_update' question.id %}" title="Edit the Question">Edit</a>
|
<button id="save-annotations">Save Annotations</button>
|
||||||
<a href="{% url 'anatomy:question_clone' question.id %}" title="Clone the Question">Clone</a>
|
<div id="dicom-image" class="dicom-image" data-url="https://www.penracourses.org.uk{{ question.image.url}}"
|
||||||
<a href="{% url 'anatomy:question_delete' pk=question.pk %}" title="Delete the Question">Delete</a>
|
|
||||||
<a href="#"
|
|
||||||
onclick="return window.create_popup_window('{% url 'feedback_create' question_type='anatomy' pk=question.pk %}')">
|
|
||||||
Add Note</a>
|
|
||||||
|
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<a href="{% url 'admin:anatomy_anatomyquestion_change' question.id %}"
|
|
||||||
title="Edit the Question using the admin interface">Admin Edit</a>
|
|
||||||
<a href="{% url 'anatomy:question_user_answers' question.id %}" title="View user answers associated with this question">User answers</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if exam %}
|
|
||||||
<div>
|
|
||||||
|
|
||||||
{% if previous > -1 %}
|
|
||||||
<a href="{% url 'anatomy:exam_question_detail' exam.id previous %}">Previous question</a>
|
|
||||||
{% endif %}
|
|
||||||
Viewing question as part of exam: <a href="{% url 'anatomy:exam_overview' exam.id %}">{{exam.name}}</a> [{{pos}}/{{exam_length}}]
|
|
||||||
{% if next %}
|
|
||||||
<a href="{% url 'anatomy:exam_question_detail' exam.id next %}">Next question</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<button id="save-annotations">Save Annotations</button>
|
|
||||||
<div id="dicom-image" class="dicom-image" data-url="https://www.penracourses.org.uk{{ question.image.url}}"
|
|
||||||
data-annotations='{{question.image_annotations}}' data-edit_annotation=true></div>
|
data-annotations='{{question.image_annotations}}' data-edit_annotation=true></div>
|
||||||
<div class="question">
|
<div class="question">
|
||||||
<div class="date">
|
<div class="date">
|
||||||
Created: {{ question.created_date|date:"d/m/Y" }}
|
Created: {{ question.created_date|date:"d/m/Y" }}
|
||||||
</div>
|
</div>
|
||||||
@@ -108,8 +83,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
|
||||||
//$("#annotation-json-toggle").click(() => {
|
//$("#annotation-json-toggle").click(() => {
|
||||||
@@ -167,5 +142,5 @@
|
|||||||
return json_tool_state;
|
return json_tool_state;
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
<div class="floating-header">
|
||||||
|
<a href="{% url 'anatomy:anatomy_question_update' question.id %}" title="Edit the Question">Edit</a>
|
||||||
|
<a href="{% url 'anatomy:question_clone' question.id %}" title="Clone the Question">Clone</a>
|
||||||
|
<a href="{% url 'anatomy:question_delete' pk=question.pk %}" title="Delete the Question">Delete</a>
|
||||||
|
<a href="{% url 'anatomy:question_answer_update' pk=question.pk %}" title="Update the question answers">Edit Answers</a>
|
||||||
|
<a href="#"
|
||||||
|
onclick="return window.create_popup_window('{% url 'feedback_create' question_type='anatomy' pk=question.pk %}')">
|
||||||
|
Add Note</a>
|
||||||
|
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
|
<a href="{% url 'admin:anatomy_anatomyquestion_change' question.id %}"
|
||||||
|
title="Edit the Question using the admin interface">Admin Edit</a>
|
||||||
|
<a href="{% url 'anatomy:question_user_answers' question.id %}" title="View user answers associated with this question">User answers</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if exam %}
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{% if previous > -1 %}
|
||||||
|
<a href="{% url 'anatomy:exam_question_detail' exam.id previous %}">Previous question</a>
|
||||||
|
{% endif %}
|
||||||
|
Viewing question as part of exam: <a href="{% url 'anatomy:exam_overview' exam.id %}">{{exam.name}}</a> [{{pos}}/{{exam_length}}]
|
||||||
|
{% if next %}
|
||||||
|
<a href="{% url 'anatomy:exam_question_detail' exam.id next %}">Next question</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends 'anatomy/base.html' %}
|
{% extends 'anatomy/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% include 'anatomy/question_link_header.html' %}
|
||||||
<h2>{{question}}</h2>
|
<h2>{{question}}</h2>
|
||||||
|
|
||||||
{% if answer_compare %}
|
{% if answer_compare %}
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ urlpatterns = [
|
|||||||
views.AnatomyQuestionUpdate.as_view(),
|
views.AnatomyQuestionUpdate.as_view(),
|
||||||
name="anatomy_question_update",
|
name="anatomy_question_update",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"question/<int:pk>/update_answers",
|
||||||
|
views.AnatomyQuestionAnswerUpdate.as_view(),
|
||||||
|
name="question_answer_update",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"question/<int:pk>/save_annotation",
|
"question/<int:pk>/save_annotation",
|
||||||
views.question_save_annotation,
|
views.question_save_annotation,
|
||||||
|
|||||||
+65
-23
@@ -28,6 +28,7 @@ from dal import autocomplete
|
|||||||
|
|
||||||
from .forms import (
|
from .forms import (
|
||||||
AnatomyAnswerForm,
|
AnatomyAnswerForm,
|
||||||
|
AnatomyQuestionAnswerForm,
|
||||||
AnswerFormSet,
|
AnswerFormSet,
|
||||||
AnswerUpdateFormSet,
|
AnswerUpdateFormSet,
|
||||||
BodyPartForm,
|
BodyPartForm,
|
||||||
@@ -247,7 +248,7 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
|
|||||||
elif not unmarked_exam_answers_only:
|
elif not unmarked_exam_answers_only:
|
||||||
mark_url = "anatomy:mark_all"
|
mark_url = "anatomy:mark_all"
|
||||||
|
|
||||||
questions = exam.exam_questions.all()
|
questions = exam.exam_questions.all().prefetch_related("answers")
|
||||||
|
|
||||||
n = sk
|
n = sk
|
||||||
|
|
||||||
@@ -358,6 +359,7 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
|
|||||||
for suggest_incorrect in question.answer_suggest_incorrect:
|
for suggest_incorrect in question.answer_suggest_incorrect:
|
||||||
if suggest_incorrect in ans:
|
if suggest_incorrect in ans:
|
||||||
answer_suggest_incorrect.append(ans)
|
answer_suggest_incorrect.append(ans)
|
||||||
|
break
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
@@ -554,6 +556,42 @@ class AnatomyQuestionCreate(AnatomyQuestionCreateBase):
|
|||||||
# return super().form_valid(form)
|
# return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class AnatomyQuestionAnswerUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView):
|
||||||
|
model = AnatomyQuestion
|
||||||
|
form_class = AnatomyQuestionAnswerForm
|
||||||
|
template_name = "anatomy/anatomyquestionanswer_form.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(AnatomyQuestionAnswerUpdate, self).get_context_data(**kwargs)
|
||||||
|
if self.request.POST:
|
||||||
|
context["answer_formset"] = AnswerUpdateFormSet(
|
||||||
|
self.request.POST, self.request.FILES, instance=self.object
|
||||||
|
)
|
||||||
|
context["answer_formset"].full_clean()
|
||||||
|
else:
|
||||||
|
context["answer_formset"] = AnswerUpdateFormSet(instance=self.object)
|
||||||
|
context["question"] = context["object"]
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
|
||||||
|
self.object = form.save(commit=False)
|
||||||
|
self.object.save()
|
||||||
|
|
||||||
|
#form.instance.author.add(self.request.user.id)
|
||||||
|
|
||||||
|
context = self.get_context_data(form=form)
|
||||||
|
formset = context["answer_formset"]
|
||||||
|
# logger.debug(formset.is_valid())
|
||||||
|
if formset.is_valid():
|
||||||
|
response = super().form_valid(form)
|
||||||
|
formset.instance = self.object
|
||||||
|
formset.save()
|
||||||
|
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
# class AnatomyQuestionUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin,
|
# class AnatomyQuestionUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin,
|
||||||
class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView):
|
class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView):
|
||||||
model = AnatomyQuestion
|
model = AnatomyQuestion
|
||||||
@@ -566,13 +604,14 @@ class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateV
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(AnatomyQuestionUpdate, self).get_context_data(**kwargs)
|
context = super(AnatomyQuestionUpdate, self).get_context_data(**kwargs)
|
||||||
if self.request.POST:
|
#if self.request.POST:
|
||||||
context["answer_formset"] = AnswerUpdateFormSet(
|
# context["answer_formset"] = AnswerUpdateFormSet(
|
||||||
self.request.POST, self.request.FILES, instance=self.object
|
# self.request.POST, self.request.FILES, instance=self.object
|
||||||
)
|
# )
|
||||||
context["answer_formset"].full_clean()
|
# context["answer_formset"].full_clean()
|
||||||
else:
|
#else:
|
||||||
context["answer_formset"] = AnswerUpdateFormSet(instance=self.object)
|
# context["answer_formset"] = AnswerUpdateFormSet(instance=self.object)
|
||||||
|
context["question"] = context["object"]
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
@@ -589,23 +628,24 @@ class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateV
|
|||||||
form.instance.author.add(self.request.user.id)
|
form.instance.author.add(self.request.user.id)
|
||||||
|
|
||||||
context = self.get_context_data(form=form)
|
context = self.get_context_data(form=form)
|
||||||
formset = context["answer_formset"]
|
#formset = context["answer_formset"]
|
||||||
# logger.debug(formset.is_valid())
|
return super().form_valid(form)
|
||||||
if formset.is_valid():
|
## logger.debug(formset.is_valid())
|
||||||
response = super().form_valid(form)
|
#if formset.is_valid():
|
||||||
formset.instance = self.object
|
# response = super().form_valid(form)
|
||||||
formset.save()
|
# formset.instance = self.object
|
||||||
|
# formset.save()
|
||||||
|
|
||||||
# restore exam orders
|
# # restore exam orders
|
||||||
#for exam in self.object.exams.all():
|
# #for exam in self.object.exams.all():
|
||||||
# if exam in exam_orders and self.object in exam_orders[exam]:
|
# # if exam in exam_orders and self.object in exam_orders[exam]:
|
||||||
# print(exam_orders[exam])
|
# # print(exam_orders[exam])
|
||||||
# exam.exam_questions.set(exam_orders[exam])
|
# # exam.exam_questions.set(exam_orders[exam])
|
||||||
# exam.save()
|
# # exam.save()
|
||||||
|
|
||||||
return response
|
# return response
|
||||||
else:
|
#else:
|
||||||
return super().form_invalid(form)
|
# return super().form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
class QuestionClone(AnatomyQuestionCreateBase):
|
class QuestionClone(AnatomyQuestionCreateBase):
|
||||||
@@ -625,6 +665,8 @@ class QuestionClone(AnatomyQuestionCreateBase):
|
|||||||
|
|
||||||
# initial_data["exams"] = list(exams)
|
# initial_data["exams"] = list(exams)
|
||||||
|
|
||||||
|
# TODO: clone answers?
|
||||||
|
|
||||||
return initial_data
|
return initial_data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -181,6 +181,11 @@ class QuestionBase(models.Model):
|
|||||||
"""If this makes sense in the question/answer context override"""
|
"""If this makes sense in the question/answer context override"""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_author_objects(self):
|
||||||
|
"""Returns a comma seperated text list of authors"""
|
||||||
|
authors = [i for i in self.author.all()]
|
||||||
|
return authors
|
||||||
|
|
||||||
|
|
||||||
class SeriesImageBase(models.Model):
|
class SeriesImageBase(models.Model):
|
||||||
"""
|
"""
|
||||||
@@ -320,7 +325,7 @@ class SeriesBase(models.Model):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_author_objects(self):
|
def get_author_objects(self):
|
||||||
"""Returns a comma seperated text list of authors"""
|
"""Returns a list of authors"""
|
||||||
if self.author:
|
if self.author:
|
||||||
return self.author.all()
|
return self.author.all()
|
||||||
else:
|
else:
|
||||||
@@ -703,6 +708,12 @@ class ExamCollectionGenericBase(models.Model):
|
|||||||
new.save()
|
new.save()
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
def get_question_cid_user_answer(self, question_index, cid):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_question_user_user_answer(self, question_index, user):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_cid_user_exams(
|
def get_cid_user_exams(
|
||||||
self, cid_user: "CidUser" = None, user_user: User = None
|
self, cid_user: "CidUser" = None, user_user: User = None
|
||||||
) -> "CidUserExam":
|
) -> "CidUserExam":
|
||||||
@@ -833,6 +844,10 @@ class ExamBase(ExamCollectionGenericBase):
|
|||||||
def get_question_index(self, question):
|
def get_question_index(self, question):
|
||||||
return list(self.exam_questions.all()).index(question)
|
return list(self.exam_questions.all()).index(question)
|
||||||
|
|
||||||
|
def get_question_by_index(self, index:int):
|
||||||
|
# There must be a better way to do this
|
||||||
|
return list(self.exam_questions.all())[index]
|
||||||
|
|
||||||
def get_cid_user_score(self, cid_user):
|
def get_cid_user_score(self, cid_user):
|
||||||
c = "c/" + str(cid_user)
|
c = "c/" + str(cid_user)
|
||||||
if c in self.user_scores:
|
if c in self.user_scores:
|
||||||
|
|||||||
+41
-13
@@ -11,9 +11,19 @@ urlpatterns = [
|
|||||||
# path('', views.question_list, name='question_list'),
|
# path('', views.question_list, name='question_list'),
|
||||||
path("examination/", views.ExaminationView.as_view(), name="examination_view"),
|
path("examination/", views.ExaminationView.as_view(), name="examination_view"),
|
||||||
path("examination/<int:pk>", views.examination_detail, name="examination_detail"),
|
path("examination/<int:pk>", views.examination_detail, name="examination_detail"),
|
||||||
path("examination/<int:pk>/delete", views.ExaminationDelete.as_view(), name="examination_delete"),
|
path(
|
||||||
path("examination/<int:pk>/update", views.ExaminationUpdate.as_view(), name="examination_update"),
|
"examination/<int:pk>/delete",
|
||||||
path("examination/<int:pk>/merge", views.examination_merge, name="examination_merge"),
|
views.ExaminationDelete.as_view(),
|
||||||
|
name="examination_delete",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"examination/<int:pk>/update",
|
||||||
|
views.ExaminationUpdate.as_view(),
|
||||||
|
name="examination_update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"examination/<int:pk>/merge", views.examination_merge, name="examination_merge"
|
||||||
|
),
|
||||||
path("examination/create/", views.create_examination, name="create_examination"),
|
path("examination/create/", views.create_examination, name="create_examination"),
|
||||||
path(
|
path(
|
||||||
"examination/ajax/get_examination_id",
|
"examination/ajax/get_examination_id",
|
||||||
@@ -60,7 +70,11 @@ urlpatterns = [
|
|||||||
name="cid_group_detail",
|
name="cid_group_detail",
|
||||||
),
|
),
|
||||||
path("cids/group/<int:pk>/email", views.group_email, name="group_email"),
|
path("cids/group/<int:pk>/email", views.group_email, name="group_email"),
|
||||||
path("cids/group/<int:pk>/exams", views.CidGroupExamUpdate.as_view(), name="cid_group_exams"),
|
path(
|
||||||
|
"cids/group/<int:pk>/exams",
|
||||||
|
views.CidGroupExamUpdate.as_view(),
|
||||||
|
name="cid_group_exams",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"cids/group/<int:pk>/email_results",
|
"cids/group/<int:pk>/email_results",
|
||||||
views.group_email_results,
|
views.group_email_results,
|
||||||
@@ -106,7 +120,11 @@ urlpatterns = [
|
|||||||
views.user_group_view_detail,
|
views.user_group_view_detail,
|
||||||
name="user_group_detail",
|
name="user_group_detail",
|
||||||
),
|
),
|
||||||
path("user/group/<int:pk>/exams", views.UserGroupExamUpdate.as_view(), name="user_group_exams"),
|
path(
|
||||||
|
"user/group/<int:pk>/exams",
|
||||||
|
views.UserGroupExamUpdate.as_view(),
|
||||||
|
name="user_group_exams",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"user/group/<int:pk>/update",
|
"user/group/<int:pk>/update",
|
||||||
views.UserUserGroupUpdate.as_view(),
|
views.UserUserGroupUpdate.as_view(),
|
||||||
@@ -191,6 +209,16 @@ def generic_exam_urls(generic_exam_view: GenericExamViews):
|
|||||||
generic_exam_view.exam_question_detail,
|
generic_exam_view.exam_question_detail,
|
||||||
name="exam_question_detail",
|
name="exam_question_detail",
|
||||||
),
|
),
|
||||||
|
#path(
|
||||||
|
# "exam/<int:pk>/question/<int:sk>/answer/<str:user_or_cid>",
|
||||||
|
# generic_exam_view.exam_question_user_answer,
|
||||||
|
# name="exam_question_user_answer",
|
||||||
|
#),
|
||||||
|
path(
|
||||||
|
"exam/<int:pk>/question/<int:sk>/answer/<str:c_or_u>/<str:user_or_cid>",
|
||||||
|
generic_exam_view.exam_question_user_answer,
|
||||||
|
name="exam_question_user_answer",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"exam/<int:exam_id>/user/<int:user_id>",
|
"exam/<int:exam_id>/user/<int:user_id>",
|
||||||
generic_exam_view.exam_user,
|
generic_exam_view.exam_user,
|
||||||
@@ -333,26 +361,26 @@ def generic_exam_urls(generic_exam_view: GenericExamViews):
|
|||||||
generic_exam_view.exam_question_json_unbased_cid,
|
generic_exam_view.exam_question_json_unbased_cid,
|
||||||
name="exam_question_json_unbased_cid",
|
name="exam_question_json_unbased_cid",
|
||||||
),
|
),
|
||||||
#path(
|
# path(
|
||||||
# "exam/json/<int:pk>/<int:sk>",
|
# "exam/json/<int:pk>/<int:sk>",
|
||||||
# generic_exam_view.exam_question_json,
|
# generic_exam_view.exam_question_json,
|
||||||
# name="exam_question_json",
|
# name="exam_question_json",
|
||||||
#),
|
# ),
|
||||||
#path(
|
# path(
|
||||||
# "exam/json/<int:pk>/<int:sk>/unbased",
|
# "exam/json/<int:pk>/<int:sk>/unbased",
|
||||||
# generic_exam_view.exam_question_json_unbased,
|
# generic_exam_view.exam_question_json_unbased,
|
||||||
# name="exam_question_json_unbased",
|
# name="exam_question_json_unbased",
|
||||||
#),
|
# ),
|
||||||
#path(
|
# path(
|
||||||
# "exam/json/<int:pk>/<int:cid>/<str:passcode>/<int:sk>",
|
# "exam/json/<int:pk>/<int:cid>/<str:passcode>/<int:sk>",
|
||||||
# generic_exam_view.exam_question_json_cid,
|
# generic_exam_view.exam_question_json_cid,
|
||||||
# name="exam_question_json_cid",
|
# name="exam_question_json_cid",
|
||||||
#),
|
# ),
|
||||||
#path(
|
# path(
|
||||||
# "exam/json/<int:pk>/<int:cid>/<str:passcode>/<int:sk>/unbased",
|
# "exam/json/<int:pk>/<int:cid>/<str:passcode>/<int:sk>/unbased",
|
||||||
# generic_exam_view.exam_question_json_unbased_cid,
|
# generic_exam_view.exam_question_json_unbased_cid,
|
||||||
# name="exam_question_json_unbased_cid",
|
# name="exam_question_json_unbased_cid",
|
||||||
#),
|
# ),
|
||||||
path(
|
path(
|
||||||
"exam/json/<int:pk>/recreate",
|
"exam/json/<int:pk>/recreate",
|
||||||
generic_exam_view.exam_json_recreate,
|
generic_exam_view.exam_json_recreate,
|
||||||
|
|||||||
@@ -1353,6 +1353,35 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
{"filter": filter, "app_name": self.app_name},
|
{"filter": filter, "app_name": self.app_name},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def exam_question_user_answer(self, request, pk: int, sk: int, c_or_u: str, user_or_cid: str):
|
||||||
|
exam: ExamBase = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|
||||||
|
#question = exam.exam_questions.all()[sk]
|
||||||
|
|
||||||
|
if c_or_u == "u":
|
||||||
|
user = get_object_or_404(User,pk=user_or_cid)
|
||||||
|
answer = exam.get_question_user_user_answer(sk, user)
|
||||||
|
elif c_or_u == "c":
|
||||||
|
#cid_user = CidUser.objects.filter(cid=user_or_cid)
|
||||||
|
answer =exam.get_question_cid_user_answer(sk, user_or_cid)
|
||||||
|
else:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
print(answer)
|
||||||
|
return HttpResponse(answer)
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def exam_question_cid_user_answer(self, request, pk: int, sk: int, cid: str):
|
||||||
|
exam: ExamBase = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|
||||||
|
#question = exam.exam_questions.all()[sk]
|
||||||
|
|
||||||
|
cid_user = CidUser.objects.filter(cid=cid)
|
||||||
|
answer =exam.get_question_cid_user_answer(sk, cid_user)
|
||||||
|
|
||||||
|
print(answer)
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def exam_question_detail(self, request, pk, sk):
|
def exam_question_detail(self, request, pk, sk):
|
||||||
exam = get_object_or_404(self.Exam, pk=pk)
|
exam = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|||||||
@@ -1110,3 +1110,11 @@ table .peninsula-trainee::before {
|
|||||||
background-color: #52057b;
|
background-color: #52057b;
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-on-hover {
|
||||||
|
opacity: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-on-hover:hover {
|
||||||
|
opacity: 100%;
|
||||||
|
}
|
||||||
@@ -64,6 +64,11 @@ class RapidCreationDefaultForm(ModelForm):
|
|||||||
exclude = ["author"]
|
exclude = ["author"]
|
||||||
|
|
||||||
|
|
||||||
|
class RapidQuestionAnswerForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Rapid
|
||||||
|
fields = []
|
||||||
|
|
||||||
class RapidForm(ModelForm):
|
class RapidForm(ModelForm):
|
||||||
|
|
||||||
# exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
|
# exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
|
||||||
|
|||||||
@@ -1,29 +1,6 @@
|
|||||||
{% extends 'rapids/base.html' %}
|
{% extends 'rapids/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% include "rapids/question_link_header.html" %}
|
||||||
<div class="floating-header">
|
{% include 'rapids/question_display_block.html' %}
|
||||||
|
|
||||||
<a href="{% url 'rapids:rapid_update' pk=question.pk %}" title="Edit the Rapid">Edit</a>
|
|
||||||
<a href="{% url 'rapids:rapid_clone' pk=question.pk %}" title="Clone the Rapid (duplicate everything but the images)">Clone</a>
|
|
||||||
<a href="{% url 'rapids:question_delete' pk=question.pk %}" title="Delete the Rapid">Delete</a>
|
|
||||||
<a href="#" onclick="return window.create_popup_window('{% url 'feedback_create' question_type='rapid' pk=question.pk %}')"> Add Note</a>
|
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<a href="{% url 'admin:rapids_rapid_change' question.id %}" title="Edit the Rapid using the admin interface">Admin Edit</a>
|
|
||||||
<a href="{% url 'rapids:question_user_answers' question.id %}" title="View user answers associated with this question">User answers</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if exam %}
|
|
||||||
<div>
|
|
||||||
|
|
||||||
{% if previous > -1 %}
|
|
||||||
<a href="{% url 'rapids:exam_question_detail' exam.id previous %}">Previous question</a>
|
|
||||||
{% endif %}
|
|
||||||
Viewing question as part of exam: <a href="{% url 'rapids:exam_overview' exam.id %}">{{exam.name}}</a> [{{pos}}/{{exam_length}}]
|
|
||||||
{% if next %}
|
|
||||||
<a href="{% url 'rapids:exam_question_detail' exam.id next %}">Next question</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% include 'rapids/question_display_block.html' %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
<div class="floating-header">
|
||||||
|
|
||||||
|
<a href="{% url 'rapids:rapid_update' pk=question.pk %}" title="Edit the Rapid">Edit</a>
|
||||||
|
<a href="{% url 'rapids:rapid_clone' pk=question.pk %}" title="Clone the Rapid (duplicate everything but the images)">Clone</a>
|
||||||
|
<a href="{% url 'rapids:question_delete' pk=question.pk %}" title="Delete the Rapid">Delete</a>
|
||||||
|
<a href="{% url 'rapids:question_answer_update' pk=question.pk %}" title="Update the question answers">Edit Answers</a>
|
||||||
|
<a href="#" onclick="return window.create_popup_window('{% url 'feedback_create' question_type='rapid' pk=question.pk %}')"> Add Note</a>
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
|
<a href="{% url 'admin:rapids_rapid_change' question.id %}" title="Edit the Rapid using the admin interface">Admin Edit</a>
|
||||||
|
<a href="{% url 'rapids:question_user_answers' question.id %}" title="View user answers associated with this question">User answers</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if exam %}
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{% if previous > -1 %}
|
||||||
|
<a href="{% url 'rapids:exam_question_detail' exam.id previous %}">Previous question</a>
|
||||||
|
{% endif %}
|
||||||
|
Viewing question as part of exam: <a href="{% url 'rapids:exam_overview' exam.id %}">{{exam.name}}</a> [{{pos}}/{{exam_length}}]
|
||||||
|
{% if next %}
|
||||||
|
<a href="{% url 'rapids:exam_question_detail' exam.id next %}">Next question</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
@@ -360,6 +360,11 @@
|
|||||||
{{ form.media }}
|
{{ form.media }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
{% if object %}
|
||||||
|
{% include "rapids/question_link_header.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h2>Submit Rapid</h2>
|
<h2>Submit Rapid</h2>
|
||||||
<a href="{% url 'rapids:rapid_create_defaults' %}">Edit defaults</a>
|
<a href="{% url 'rapids:rapid_create_defaults' %}">Edit defaults</a>
|
||||||
<p>
|
<p>
|
||||||
@@ -415,7 +420,6 @@ the feedback image box is checked they will not be displayed when taking the que
|
|||||||
</div>
|
</div>
|
||||||
{{ image_formset.management_form }}
|
{{ image_formset.management_form }}
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
<input type="submit" class="submit-button" value="Submit and Clone" name="submit-clone">
|
|
||||||
</form>
|
</form>
|
||||||
<div id="empty_form" style="display:none">
|
<div id="empty_form" style="display:none">
|
||||||
<ul class='no_error image-formset'>
|
<ul class='no_error image-formset'>
|
||||||
|
|||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
{% extends "rapids/base.html" %}
|
||||||
|
{% load static from static %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
let csrf_token = "{{csrf_token}}";
|
||||||
|
|
||||||
|
function add_answers_input_form() {
|
||||||
|
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
||||||
|
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
||||||
|
$(`#id_answers-${form_idx}-status`).val(2);
|
||||||
|
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
$('#add_more_answers').click(() => {
|
||||||
|
add_answers_input_form()
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ form.media }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if object %}
|
||||||
|
{% include "rapids/question_link_header.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h2>Update Question Answers</h2>
|
||||||
|
<form action="" method="post" enctype="multipart/form-data" id="rapid-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h3>Answers:</h3>
|
||||||
|
<div id="answer_form_set">
|
||||||
|
{% for form in answer_formset %}
|
||||||
|
<ul class="no-error answer-formset">
|
||||||
|
{{form.non_field_errors}}
|
||||||
|
{{form.errors}}
|
||||||
|
{{ form.as_ul }}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{{ answer_formset.management_form }}
|
||||||
|
<input type="button" value="Add More Answers" id="add_more_answers">
|
||||||
|
<p>
|
||||||
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<div id="answer_empty_form" style="display:none">
|
||||||
|
<ul class='no_error answer-formset'>
|
||||||
|
{{ answer_formset.empty_form.as_ul }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -81,6 +81,11 @@ urlpatterns = [
|
|||||||
views.RapidUpdate.as_view(),
|
views.RapidUpdate.as_view(),
|
||||||
name="rapid_update",
|
name="rapid_update",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"question/<int:pk>/update_answers",
|
||||||
|
views.RapidAnswerUpdate.as_view(),
|
||||||
|
name="question_answer_update",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"user_answers/",
|
"user_answers/",
|
||||||
views.UserAnswerTableView.as_view(),
|
views.UserAnswerTableView.as_view(),
|
||||||
|
|||||||
+38
-1
@@ -24,6 +24,7 @@ from .forms import (
|
|||||||
RapidForm,
|
RapidForm,
|
||||||
MarkRapidQuestionForm,
|
MarkRapidQuestionForm,
|
||||||
ImageFormSet,
|
ImageFormSet,
|
||||||
|
RapidQuestionAnswerForm,
|
||||||
RegionForm,
|
RegionForm,
|
||||||
AbnormalityForm,
|
AbnormalityForm,
|
||||||
ExaminationForm,
|
ExaminationForm,
|
||||||
@@ -330,9 +331,44 @@ class RapidCreate(RapidCreateBase):
|
|||||||
# form.instance.author.add(self.request.user.id)
|
# form.instance.author.add(self.request.user.id)
|
||||||
# return super().form_valid(form)
|
# return super().form_valid(form)
|
||||||
|
|
||||||
|
class RapidAnswerUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView):
|
||||||
|
model = Rapid
|
||||||
|
form_class = RapidQuestionAnswerForm
|
||||||
|
template_name = "rapids/rapidquestionanswer_form.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(RapidAnswerUpdate, self).get_context_data(**kwargs)
|
||||||
|
if self.request.POST:
|
||||||
|
context["answer_formset"] = AnswerUpdateFormSet(
|
||||||
|
self.request.POST, self.request.FILES, instance=self.object
|
||||||
|
)
|
||||||
|
context["answer_formset"].full_clean()
|
||||||
|
else:
|
||||||
|
context["answer_formset"] = AnswerUpdateFormSet(instance=self.object)
|
||||||
|
context["question"] = context["object"]
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
|
||||||
|
self.object = form.save(commit=False)
|
||||||
|
self.object.save()
|
||||||
|
|
||||||
|
#form.instance.author.add(self.request.user.id)
|
||||||
|
|
||||||
|
context = self.get_context_data(form=form)
|
||||||
|
formset = context["answer_formset"]
|
||||||
|
# logger.debug(formset.is_valid())
|
||||||
|
if formset.is_valid():
|
||||||
|
response = super().form_valid(form)
|
||||||
|
formset.instance = self.object
|
||||||
|
formset.save()
|
||||||
|
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
class RapidUpdate(
|
class RapidUpdate(
|
||||||
RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView
|
RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView
|
||||||
):
|
):
|
||||||
model = Rapid
|
model = Rapid
|
||||||
form_class = RapidForm
|
form_class = RapidForm
|
||||||
@@ -360,6 +396,7 @@ class RapidUpdate(
|
|||||||
else:
|
else:
|
||||||
context["image_formset"] = ImageFormSet(instance=self.object)
|
context["image_formset"] = ImageFormSet(instance=self.object)
|
||||||
context["answer_formset"] = AnswerFormSet(instance=self.object)
|
context["answer_formset"] = AnswerFormSet(instance=self.object)
|
||||||
|
context["question"] = context["object"]
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
|||||||
@@ -19,6 +19,5 @@
|
|||||||
{{ form.as_table }}
|
{{ form.as_table }}
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
<input type="submit" class="submit-button" value="Submit and Clone" name="submit-clone">
|
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user