Joey Coder
Joey Coder

Reputation: 3489

Django: One function, two class-based views

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()

Upvotes: 0

Views: 123

Answers (1)

H4kor
H4kor

Reputation: 1562

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

Upvotes: 1

Related Questions