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