コード例 #1
0
class GenericQuestion(BaseModel):
    ANSWER_TYPES = [(name, name) for name in Answer.answer_types()]
    identifier = models.CharField(max_length=100, verbose_name='Variable Name')
    text = models.CharField(max_length=250)
    answer_type = models.CharField(
        max_length=100, blank=False, null=False, choices=ANSWER_TYPES)
    response_validation = models.ForeignKey(ResponseValidation, related_name='%(class)s', null=True, blank=True,
                                            verbose_name='Validation Rule')

    @classmethod
    def type_name(cls):
        return cls._meta.verbose_name.title()

    class Meta:
        abstract = True

    def validators(self):
        return Answer.get_class(self.answer_type).validators()

    def validator_names(self):
        return [v.__name__ for v in Answer.get_class(self.answer_type).validators()]

    def odk_constraint(self):
        if self.response_validation:
            return self.response_validation.get_odk_constraint(self)

    def odk_constraint_msg(self):
        if self.response_validation:
            return self.response_validation.dconstraint_message
コード例 #2
0
class QuestionTemplate(BaseModel):
    ANSWER_TYPES = [(name, name) for name in Answer.answer_types()]
    identifier = models.CharField(max_length=100,
                                  blank=False,
                                  null=True,
                                  unique=True)
    group = models.ForeignKey("HouseholdMemberGroup",
                              related_name="question_templates")
    text = models.CharField(
        max_length=150,
        blank=False,
        null=False,
        #help_text="To replace the household member's name \
        #in the question, please include the variable FAMILY_NAME in curly brackets, e.g. {{ FAMILY_NAME }}. "
    )
    answer_type = models.CharField(max_length=100,
                                   blank=False,
                                   null=False,
                                   choices=ANSWER_TYPES)
    module = models.ForeignKey("QuestionModule",
                               related_name="question_templates")

    class Meta:
        app_label = 'survey'

    def __unicode__(self):
        return "%s - %s: (%s)" % (self.identifier, self.text,
                                  self.answer_type.upper())

    def save(self, *args, **kwargs):
        if self.answer_type not in [
                MultiChoiceAnswer.choice_name(),
                MultiSelectAnswer.choice_name()
        ]:
            self.options.all().delete()
        return super(QuestionTemplate, self).save(*args, **kwargs)
コード例 #3
0
ファイル: questions.py プロジェクト: jnhdny/uSurvey
class Question(BaseModel):
    ANSWER_TYPES = [(name, name) for name in Answer.answer_types()]
    identifier = models.CharField(max_length=100,
                                  blank=False,
                                  null=True,
                                  verbose_name='Variable Name')
    text = models.CharField(
        max_length=150,
        blank=False,
        null=False,
        #help_text="To replace the household member's name \
        #in the question, please include the variable FAMILY_NAME in curly brackets, e.g. {{ FAMILY_NAME }}. "
    )
    answer_type = models.CharField(max_length=100,
                                   blank=False,
                                   null=False,
                                   choices=ANSWER_TYPES)
    group = models.ForeignKey(HouseholdMemberGroup, related_name='questions')
    batch = models.ForeignKey('Batch', related_name='batch_questions')
    module = models.ForeignKey("QuestionModule",
                               related_name="questions",
                               default='')

    class Meta:
        app_label = 'survey'
        unique_together = [
            ('identifier', 'batch'),
        ]

    def answers(self):
        return Answer.get_class(self.answer_type).objects.filter(question=self)

    def total_answers(
        self
    ):  #just utility to get number of times this question has been answered
        return Answer.get_class(
            self.answer_type).objects.filter(question=self).count()

    def is_loop_start(self):
        from survey.forms.logic import LogicForm
        return self.connecting_flows.filter(
            desc=LogicForm.BACK_TO_ACTION).exists(
            )  #actually the more correct way is to
        # check if the next is previous

    def is_loop_end(self):
        from survey.forms.logic import LogicForm
        return self.flows.filter(desc=LogicForm.BACK_TO_ACTION).exists(
        )  #actually the more correct way is
        #to check if connecting quest is asked after

    @property
    def loop_ender(self):
        try:
            from survey.forms.logic import LogicForm
            return self.connecting_flows.get(
                desc=LogicForm.BACK_TO_ACTION).question
        except QuestionFlow.DoesNotExist:
            inlines = self.batch.questions_inline()

    @property
    def looper_flow(self):
        #if self.is_loop_start() or self.is_loop_end():
        return self.batch.get_looper_flow(self)

    def loop_boundary(self):
        return self.batch.loop_back_boundaries().get(self.pk, None)

    # def loop_inlines(self):

    def delete(self, using=None):
        '''
        Delete related answers before deleting this object
        :param using:
        :return:
        '''
        answer_class = Answer.get_class(self.answer_type)
        answer_class.objects.filter(question=self).delete()
        return super(Question, self).delete(using=using)

    def display_text(self, channel=None):
        text = self.text
        if channel and channel == USSDAccess.choice_name(
        ) and self.answer_type == MultiChoiceAnswer.choice_name():
            extras = []
            #append question options
            for option in self.options.all().order_by('order'):
                extras.append(option.to_text)
            text = '%s\n%s' % (text, '\n'.join(extras))
        return text

    def next_question(self, reply):
        flows = self.flows.all()
        answer_class = Answer.get_class(self.answer_type)
        resulting_flow = None
        for flow in flows:
            if flow.validation_test:
                test_values = [arg.param for arg in flow.text_arguments]
                if getattr(answer_class,
                           flow.validation_test)(reply, *test_values) == True:
                    resulting_flow = flow
                    break
            else:
                resulting_flow = flow
        if resulting_flow:
            return resulting_flow.next_question

    def previous_inlines(self):
        inlines = self.batch.questions_inline()
        if self not in inlines:
            raise ValidationError('%s not inline' % self.identifier)
        previous = []
        for q in inlines:
            if q.identifier == self.identifier:
                break
            else:
                previous.append(q)
        return set(previous)

    def direct_sub_questions(self):
        from survey.forms.logic import LogicForm
        sub_flows = self.flows.filter(desc=LogicForm.SUBQUESTION_ACTION,
                                      validation_test__isnull=False)
        return OrderedSet([flow.next_question for flow in sub_flows])

    def conditional_flows(self):
        return self.flows.filter(validation_test__isnull=False)

    def preceeding_conditional_flows(self):
        return self.connecting_flows.filter(validation_test__isnull=False)

    def __unicode__(self):
        return "%s - %s: (%s)" % (self.identifier, self.text,
                                  self.answer_type.upper())

    def save(self, *args, **kwargs):
        if self.answer_type not in [
                MultiChoiceAnswer.choice_name(),
                MultiSelectAnswer.choice_name()
        ]:
            self.options.all().delete()
        return super(Question, self).save(*args, **kwargs)

    @classmethod
    def zombies(cls, batch):
        #these are the batch questions that do not belong to any flow in any way
        survey_questions = batch.survey_questions
        return batch.batch_questions.exclude(
            pk__in=[q.pk for q in survey_questions])

    def hierarchical_result_for(self, location_parent, survey):
        locations = location_parent.get_children().order_by('name')[:10]
        answers = self.multichoiceanswer.all()
        return self._format_answer(locations, answers, survey)

    def _format_answer(self, locations, answers, survey):
        question_options = self.options.all()
        data = OrderedDict()
        for location in locations:
            households = Household.all_households_in(location, survey)
            data[location] = {
                option.text: answers.filter(
                    value=option,
                    interview__householdmember__household__in=households).
                count()
                for option in question_options
            }
        return data
コード例 #4
0
ファイル: batch.py プロジェクト: EswarSakamuri/mymics
from django.db import models
from django.db.models import Max
from survey.models.householdgroups import HouseholdMemberGroup
from survey.models.locations import Location
from survey.models.surveys import Survey
from survey.models.base import BaseModel
from survey.utils.views_helper import get_descendants
from survey.models.questions import Question, QuestionFlow
from survey.models.access_channels import InterviewerAccess
# from survey.models.enumeration_area import EnumerationArea
from survey.models.interviews import AnswerAccessDefinition, Answer
from survey.models.access_channels import ODKAccess
from ordered_set import OrderedSet

ALL_GROUPS = HouseholdMemberGroup.objects.all()
ALL_ANSWERS = Answer.answer_types()
class Batch(BaseModel):
    order = models.PositiveIntegerField(max_length=2, null=True)
    name = models.CharField(max_length=100, blank=False, null=True)
    description = models.CharField(max_length=300, blank=True, null=True)
    survey = models.ForeignKey(Survey, null=True, related_name="batches")
#     eas = models.ManyToManyField(EnumerationArea, related_name='batches', null=True) #enumeration areas for which this Batch is open
#     group = models.ForeignKey("HouseholdMemberGroup", null=True, related_name="question_group")
    start_question = models.OneToOneField(Question, related_name='starter_batch', null=True, blank=True, on_delete=models.SET_NULL)
    BATCH_IS_OPEN_MESSAGE = "Batch cannot be deleted because it is open in %s."
    BATCH_HAS_ANSWERS_MESSAGE = "Batch cannot be deleted because it has responses."

    class Meta:
        app_label = 'survey'
        unique_together = [('survey', 'name',) ]
        
コード例 #5
0
ファイル: batch.py プロジェクト: rajkumarenmu/uSurvey
from survey.models.base import BaseModel
from survey.utils.views_helper import get_descendants
from survey.models.questions import Question, QuestionFlow
from survey.forms.logic import LogicForm
from survey.models.access_channels import InterviewerAccess
# from survey.models.enumeration_area import EnumerationArea
from survey.models.interviews import AnswerAccessDefinition, Answer
from survey.models.access_channels import ODKAccess
from django.core.exceptions import ValidationError
from ordered_set import OrderedSet
from collections import OrderedDict
from cacheops import cached_as
from django.conf import settings

ALL_GROUPS = HouseholdMemberGroup.objects.all()
ALL_ANSWERS = Answer.answer_types()


class Batch(BaseModel):
    order = models.PositiveIntegerField(null=True)
    name = models.CharField(max_length=100,
                            blank=False,
                            null=True,
                            db_index=True)
    description = models.CharField(max_length=300, blank=True, null=True)
    survey = models.ForeignKey(Survey, null=True, related_name="batches")
    #     eas = models.ManyToManyField(EnumerationArea, related_name='batches', null=True) #enumeration areas for which this Batch is open
    #     group = models.ForeignKey("HouseholdMemberGroup", null=True, related_name="question_group")
    start_question = models.OneToOneField(Question,
                                          related_name='starter_batch',
                                          null=True,