Is there a way reach to grandchild count with related name in django?

Solution 1:

It is not a good idea to that in such a way, since you here will eventually have an N+1 problem: you will make N+1 queries to the database: one query to fetch all the surveys, and N extra queries to fetch all the SurveyCollectors. If you count grandchildren, it will even be worse.

You can simply annotate your queryset, like:

from django.db.models import Count

def some_view(request):
    surveys = Survey.objects.annotate(
        nresponse=Count('survey_collector_survey__surveyresponse_collector')
    )
    # …
    return render(request, 'some_template.html',{'surveys': surveys})

Now the Survey objects that arise from this queryset will have an extra attribute .nresponse that you can then use when rendering the template:

{% for survey in surveys %}
<tr>
    <th scope="row">{{ survey.name }}</th>
    <td align="center">{{ survey.nresponse }}</td>
</tr>
{% endfor %}

Solution 2:

You can define a property in your Survey model.

class Survey(models.Model):
    name = ............

    @property
    def response_count(self):
        return SurveyResponse.objects.filter(collector__survey__pk = self.pk).aggregate(Count('collector'))['collector__count']

class SurveyCollector(models.Model):
    survey = ..........

class SurveyResponse(models.Model):
    collector = ...........

Now in your templates, you can directly use this property.

<td align="center">{{ survey.response }}</td>

Note: Take care of the double underscores (__)