예제 #1
0
    def get_steps(self, funnel: Funnel) -> List[Dict[str, Any]]:
        # for some reason, rest_framework executes SerializerMethodField multiple times,
        # causing lots of slow queries.
        # Seems a known issue: https://stackoverflow.com/questions/55023511/serializer-being-called-multiple-times-django-python
        if hasattr(funnel, 'steps_cache'):
            return {}
        funnel.steps_cache = True  # type: ignore

        funnel_steps = funnel.steps.all().prefetch_related('action')
        if self.context['view'].action != 'retrieve':
            return [{
                'id': step.id,
                'action_id': step.action.id,
                'name': step.action.name,
                'order': step.order
            } for step in funnel_steps]

        if len(funnel_steps) == 0:
            return []
        annotations = {}
        for step in funnel_steps:
            annotations['step_{}'.format(step.order)] = Subquery(
                Event.objects.filter_by_action(step.action) # type: ignore
                    .annotate(person_id=OuterRef('id'))
                    .filter(
                        distinct_id__in=Subquery(
                            PersonDistinctId.objects.filter(
                                person_id=OuterRef('person_id')
                            ).values('distinct_id')
                        ),
                        pk__gt=OuterRef('step_{}'.format(step.order-1)) if step.order > 0 else 0
                    )\
                    .order_by('pk')\
                    .values('pk')[:1]
            , output_field=models.IntegerField())

        people = Person.objects.all()\
            .annotate(**annotations)\
            .filter(step_0__isnull=False)

        people = [person for person in people]

        steps = []
        for step in funnel_steps:
            relevant_people = [
                person.id for person in people
                if getattr(person, 'step_{}'.format(step.order))
            ]
            steps.append({
                'id': step.id,
                'action_id': step.action.id,
                'name': step.action.name,
                'order': step.order,
                'people': relevant_people[:100],
                'count': len(relevant_people)
            })
        if len(steps) > 0:
            steps[0]['people'] = self._order_people_in_step(
                steps, steps[0]['people'])
        return steps
예제 #2
0
    def get_steps(self, funnel: Funnel) -> List[Dict[str, Any]]:
        # for some reason, rest_framework executes SerializerMethodField multiple times,
        # causing lots of slow queries.
        # Seems a known issue: https://stackoverflow.com/questions/55023511/serializer-being-called-multiple-times-django-python
        if hasattr(funnel, 'steps_cache'):
            return []
        funnel.steps_cache = True  # type: ignore

        if self.context['view'].action != 'retrieve' or self.context[
                'request'].GET.get('exclude_count'):
            return []
        return funnel.get_steps()
예제 #3
0
    def get_steps(self, funnel: Funnel) -> List[Dict[str, Any]]:
        # for some reason, rest_framework executes SerializerMethodField multiple times,
        # causing lots of slow queries. 
        # Seems a known issue: https://stackoverflow.com/questions/55023511/serializer-being-called-multiple-times-django-python
        if hasattr(funnel, 'steps_cache'):
            return []
        funnel.steps_cache = True # type: ignore

        funnel_steps = funnel.steps.all().order_by('order').prefetch_related('action')
        if self.context['view'].action != 'retrieve' or self.context['request'].GET.get('exclude_count'):
            return [self._serialize_step(step) for step in funnel_steps]

        if len(funnel_steps) == 0:
            return []

        people = Person.objects.all()\
            .filter(
                team_id=funnel.team_id,
                persondistinctid__distinct_id__isnull=False
            )\
            .annotate(**self._annotate_steps(
                team_id=funnel.team_id,
                funnel_steps=funnel_steps,
                date_query=request_to_date_query(self.context['request'])
            ))\
            .filter(step_0__isnull=False)\
            .distinct('pk')

        steps = []
        for index, funnel_step in enumerate(funnel_steps):
            relevant_people = [person.id for person in people if getattr(person, 'step_{}'.format(index))]
            steps.append(self._serialize_step(funnel_step, relevant_people))

        if len(steps) > 0:
            for index, _ in enumerate(steps):
                steps[index]['people'] = self._order_people_in_step(steps, steps[index]['people'])[0:100]
        return steps