0

I am currently struggling to find a better solution for get_survey_state(self, context). It is in both CBVs and I think there is a better solution than mine. Can you advise me on that?

views.py

class SurveyExpectations(AdminPermissionRequiredMixin, TemplateView):
    template_name = 'admin/surveys/expectations.html'

    def get_survey_state(self, context):
        survey = self.request.event.surveys.active_pre_event().first()
        answers = Answer.objects.filter(question__survey=survey).exists()
        context['survey_is_active'] = survey
        context['answers_exist'] = answers

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        self.get_survey_state(context)
        context['questions_and_answers'] = self.request.event.surveys.get_results(
            settings.SURVEY_PRE_EVENT
        )
        return context

class SurveyFeedback(AdminPermissionRequiredMixin, TemplateView):
    template_name = 'admin/surveys/feedback.html'

    def get_net_promoter_score(self) -> float:
        [...]
        return netpromoterscore(scores)

    def get_average_age(self) -> int:
        [...]
        return int(answers['avg']) if answers['avg'] else None

    def get_survey_state(self, context):
        survey = self.request.event.surveys.active_post_event().first()
        answers = Answer.objects.filter(question__survey=survey).exists()
        context['survey_is_active'] = survey
        context['answers_exist'] = answers

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        self.get_survey_state(context)
        context['questions_and_answers'] = self.request.event.surveys.get_results(
            settings.SURVEY_POST_EVENT
        )
        context['netpromoterscore'] = self.get_net_promoter_score()
        context['average_age'] = self.get_average_age()
        return context

models.py

class SurveyQuerySet(models.QuerySet):
    def active_pre_event(self):
        return self.filter(is_active=True, template=settings.SURVEY_PRE_EVENT)

    def active_post_event(self):
        return self.filter(is_active=True, template=settings.SURVEY_POST_EVENT)

    def get_results(self, template):
        return (
            self.get(template=template)
            .questions.exclude(focus=QuestionFocus.EMAIL)
            .all()
            .prefetch_related('answers')
        )

class Survey(TimeStampedModel):
    id = models.UUIDField([...])
    is_active = models.BooleanField([...])
    template = models.CharField([...])

    objects = SurveyQuerySet.as_manager()

1 Answer 1

1

You can use class inheritance. You create a Base Class (derived from TemplateView) in which you define all your common functionalities.

Then you can derive further views from the base class, which will inherit all functionality.

The get_survey_state uses the method self.get_survey() to allow using different retrieval methods in the derived views.

class BaseSurveyView(TemplateView):
    def get_survey_state(self, context):
        survey = self.get_survey()
        answers = Answer.objects.filter(question__survey=survey).exists()
        context['survey_is_active'] = survey
        context['answers_exist'] = answers

    def get_survey(self):
        raise NotImplementedError


class SurveyExpectations(AdminPermissionRequiredMixin, BaseSurveyView):
    template_name = 'admin/surveys/expectations.html'

    def get_survey(self):
        return self.request.event.surveys.active_pre_event().first()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        self.get_survey_state(context)
        context['questions_and_answers'] = self.request.event.surveys.get_results(
            settings.SURVEY_PRE_EVENT
        )
        return context

class SurveyFeedback(AdminPermissionRequiredMixin, BaseSurveyView):
    template_name = 'admin/surveys/feedback.html'

    def get_survey(self):
        return self.request.event.surveys.active_post_event().first()

    def get_net_promoter_score(self) -> float:
        [...]
        return netpromoterscore(scores)

    def get_average_age(self) -> int:
        [...]
        return int(answers['avg']) if answers['avg'] else None

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        self.get_survey_state(context)
        context['questions_and_answers'] = self.request.event.surveys.get_results(
            settings.SURVEY_POST_EVENT
        )
        context['netpromoterscore'] = self.get_net_promoter_score()
        context['average_age'] = self.get_average_age()
        return context
Sign up to request clarification or add additional context in comments.

5 Comments

Did you see the two different filters? active_pre_event and active_post_event would still to be different. Is it possible to integrate that as well?
They are part of the model how do they change? If you want to use different models you could do the same thing with the model and implement methods in the ChildViews that return the model to be used.
active_pre_event filters for template=settings.SURVEY_PRE_EVENT) active_post_event filters for template=settings.SURVEY_POST_EVENT). That way I can display different answers from different surveys. The second part I didn't completely understand what you mean.
Ahh ok. Now I know what you mean. I adjusted my answer. It uses a method implemented in the derived Views to get the correct survey.
Ah, smart solution. Thank you. I like that!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.