【发布时间】:2015-08-03 18:16:57
【问题描述】:
Django-cms-saq 已针对 2.4.x 进行了测试。我正在尝试更新程序以使用 3.0.X。
到目前为止,我已经更新了所有导入,但遇到了一个不寻常的错误。当我将问题(插件)添加到页面并点击发布时,它会在数据库中创建问题的两个副本(可通过管理站点查看)。删除任一副本都会从已发布的页面中删除这两个副本,但会使问题处于编辑模式。
我该如何解决这个问题?
我将在此处包含一些文件。如果您需要任何其他文件,请告诉我。
请注意,我正在尝试添加多项选择题。
来自models.py:
from django.db import models
from django.db.models import Max, Sum
from cms.models import CMSPlugin, Page, Placeholder
from cms.models.fields import PageField
from taggit.managers import TaggableManager
from djangocms_text_ckeditor.models import AbstractText
...
class Question(CMSPlugin):
QUESTION_TYPES = [
('S', 'Single-choice question'),
('M', 'Multi-choice question'),
('F', 'Free-text question'),
]
slug = models.SlugField(
help_text="A slug for identifying answers to this specific question "
"(allows multiple only for multiple languages)")
tags = TaggableManager(blank=True)
label = models.CharField(max_length=512, blank=True)
help_text = models.CharField(max_length=512, blank=True)
question_type = models.CharField(max_length=1, choices=QUESTION_TYPES)
optional = models.BooleanField(
default=False,
help_text="Only applies to free text questions",
)
depends_on_answer = models.ForeignKey(
Answer, null=True, blank=True, related_name='trigger_questions')
def copy_relations(self, oldinstance):
for answer in oldinstance.answers.all():
answer.pk = None
answer.question = self
answer.save()
self.depends_on_answer = oldinstance.depends_on_answer
@staticmethod
def all_in_tree(page):
root = page.get_root()
# Remember that there might be questions on the root page as well!
tree = root.get_descendants() | Page.objects.filter(id=root.id)
placeholders = Placeholder.objects.filter(page__in=tree)
return Question.objects.filter(placeholder__in=placeholders)
@staticmethod
def all_in_page(page):
placeholders = Placeholder.objects.filter(page=page)
return Question.objects.filter(placeholder__in=placeholders)
def score(self, answers):
if self.question_type == 'F':
return 0
elif self.question_type == 'S':
return self.answers.get(slug=answers).score
elif self.question_type == 'M':
answers_list = answers.split(',')
return sum([self.answers.get(slug=a).score for a in answers_list])
@property
def max_score(self):
if not hasattr(self, '_max_score'):
if self.question_type == "S":
self._max_score = self.answers.aggregate(
Max('score'))['score__max']
elif self.question_type == "M":
self._max_score = self.answers.aggregate(
Sum('score'))['score__sum']
else:
self._max_score = None # don't score free-text answers
return self._max_score
def percent_score_for_user(self, user):
if self.max_score:
try:
score = Submission.objects.get(
question=self.slug,
user=user,
).score
except Submission.DoesNotExist:
return 0
return 100.0 * score / self.max_score
else:
return None
def __unicode__(self):
return self.slug
...
来自 cms_plugins.py
import itertools
import operator
from django.contrib import admin
from django.utils.translation import ugettext as _
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from cms_saq.models import Question, Answer, GroupedAnswer, Submission, \
FormNav, ProgressBar, SectionedScoring, ScoreSection, BulkAnswer, \
QuestionnaireText, SubmissionSetReview
from djangocms_text_ckeditor.cms_plugins import TextPlugin
from djangocms_text_ckeditor.models import Text
from bs4 import BeautifulSoup
...
class QuestionPlugin(CMSPluginBase):
model = Question
module = "SAQ"
inlines = [AnswerAdmin]
exclude = ('question_type',)
def render(self, context, instance, placeholder):
user = context['request'].user
submission_set = None
triggered = True
depends_on = None
if instance.depends_on_answer:
depends_on = instance.depends_on_answer.pk
try:
Submission.objects.get(
user=user,
question=instance.depends_on_answer.question.slug,
answer=instance.depends_on_answer.slug,
submission_set=submission_set,
)
triggered = True
except:
triggered = False
extra = {
'question': instance,
'answers': instance.answers.all(),
'triggered': triggered,
'depends_on': depends_on,
}
if user.is_authenticated():
try:
extra['submission'] = Submission.objects.get(
user=user,
question=instance.slug,
submission_set=submission_set,
)
except Submission.DoesNotExist:
pass
context.update(extra)
return context
def save_model(self, request, obj, form, change):
obj.question_type = self.question_type
super(QuestionPlugin, self).save_model(request, obj, form, change)
...
class MultiChoiceQuestionPlugin(QuestionPlugin):
name = "Multi Choice Question"
render_template = "cms_saq/multi_choice_question.html"
question_type = "M"
exclude = ('question_type', 'help_text')
...
plugin_pool.register_plugin(SingleChoiceQuestionPlugin)
plugin_pool.register_plugin(MultiChoiceQuestionPlugin)
plugin_pool.register_plugin(DropDownQuestionPlugin)
plugin_pool.register_plugin(GroupedDropDownQuestionPlugin)
plugin_pool.register_plugin(FreeTextQuestionPlugin)
plugin_pool.register_plugin(FreeNumberQuestionPlugin)
plugin_pool.register_plugin(FormNavPlugin)
plugin_pool.register_plugin(SubmissionSetReviewPlugin)
plugin_pool.register_plugin(SectionedScoringPlugin)
plugin_pool.register_plugin(ProgressBarPlugin)
plugin_pool.register_plugin(BulkAnswerPlugin)
plugin_pool.register_plugin(SessionDefinition)
plugin_pool.register_plugin(QuestionnaireTextPlugin)
plugin_pool.register_plugin(TranslatedTextPlugin)
来自 cms_app.py:
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class CMSSaq(CMSApp):
name = _("Self Assessment")
urls = ["cms_saq.urls"]
apphook_pool.register(CMSSaq)
附加信息:
在尝试通过其 slug Question.objects.get(slug=question_slug) 获取问题对象时,此重复观察会产生问题。这样的查询应该只返回一个问题。我们得到的是返回的两个问题。
import re
from django.http import HttpResponse, HttpResponseBadRequest
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.cache import never_cache
from django.utils import simplejson, datastructures
from django.conf import settings
from cms_saq.models import Question, Answer, Submission, SubmissionSet
ANSWER_RE = re.compile(r'^[\w-]+(,[\w-]+)*$')
@require_POST
def _submit(request):
post_data = datastructures.MultiValueDict(request.POST)
submission_set_tag = post_data.pop('submission_set_tag', '')
for question_slug, answers in post_data.iteritems():
# validate the question
try:
question = Question.objects.get(
slug=question_slug,
#placeholder__page__publisher_is_draft=False,
)
except Question.DoesNotExist:
return HttpResponseBadRequest(
"Invalid question '%s'" % question_slug,
)
# check answers is a list of slugs
if question.question_type != 'F' and not ANSWER_RE.match(answers):
return HttpResponseBadRequest("Invalid answers: %s" % answers)
# validate and score the answer
try:
score = question.score(answers)
except Answer.DoesNotExist:
return HttpResponseBadRequest(
"Invalid answer '%s:%s'" % (question_slug, answers)
)
# save, but don't update submissions belonging to an existing set
filter_attrs = {
'user': request.user.id,
'question': question_slug,
'submission_set': None,
}
attrs = {'answer': answers, 'score': score}
rows = Submission.objects.filter(**filter_attrs).update(**attrs)
if not rows:
attrs.update(filter_attrs)
Submission.objects.create(**attrs)
# Create submission set if requested
if submission_set_tag:
submission_set_tag = submission_set_tag[0]
if submission_set_tag:
_create_submission_set(
request, submission_set_tag
)
return HttpResponse("OK")
【问题讨论】:
标签: django python-2.7 plugins django-cms