Как эффективно получить количество внешних ключей в модели Django?

У меня есть три таких модели:

class House(models.Model):
    name = models.CharField(max_length=150)

    def get_house_count(self):
        fetchs = 0
        for fetch in self.fetchs.all():
            fetchs += 1
        return fetchs

class Person(models.Model):
    house = models.ForeignKey(House, related_name="persons", on_delete=models.PROTECT)
    first_name = models.CharField(max_length=150)

    def get_person_count(self):
        person_fetchs = 0
        for fetch in self.person_fetchs.all():
            person_fetchs += 1
        return person_fetchs

class Fetch(models.Model):
    number = models.CharField(max_length=150)
    house = models.ForeignKey(Hourse, related_name="fetchs")
    person = models.ForeignKey(Person, related_name="person_fetchs")

Что я хочу достичь, так это получить общее количество экземпляров каждой модели в классе Fetch. Но эта операция очень дорогая (более 500 дубликатов), поскольку она создает несколько SQL-дубликатов, когда я использую библиотеку django_debug_tool. Есть ли эффективный способ сделать это? Мой файл view.py выглядит следующим образом:

class HomeView(ListView):
    queryset = Fetch.objects.select_related(
        'house', 'person', )
    template_name = "index.html"
    paginate_by = 100

А в моем шаблоне есть что-то вроде этого:

{% for obj in object_list %}
            <tr>
                <td>{{ obj.company.name }}</td>
                <td>{{ obj.house.get_house_count }}</td>                   
                <td>{{ obj.person.get_person_count }}</td>

Я также попытался использовать метод django's annotate следующим образом:

queryset = Fetch.objects.select_related(
        'house', 'person', ).annotate(
        get_count=Count('house', distinct=True),
        get_contact_count=Count('person', distinct=True)
    )

при внесении изменений в мой шаблон с помощью {{obj.get_count}} и {{obj.get_contact.count}} соответственно. Но он возвращает счетчик 1, что неверно.

Любая помощь будет оценена по достоинству.

Ок, исходя из ваших объяснений в комментариях и если я правильно понял...

Я думаю, что вам не нужно поле house в модели Fetch. Дом упоминается в Person с помощью ForeignKey. Вам также не нужно number, как вы увидите ниже.

Итак, ваши модели были бы намного проще, просто что-то вроде этих:

class House(models.Model):
    name = models.CharField(max_length=150)

class Person(models.Model):
    house = models.ForeignKey(House)
    first_name = models.CharField(max_length=150)

class Fetch(models.Model):
    person = models.ForeignKey(Person)

Теперь, предположим, у нас есть человек Том с id=1. Хозяин дома "присылал" его 5 раз для выполнения каких-либо заданий. Чтобы узнать, сколько раз его "забирали", нужно сделать следующее:

tom = Person.objects.get(id=1) # Tom's Person instance
times_fetched = Fetch.objects.filter(person=tom).count()
# Result: 5

Для подсчета элементов QuerySet после фильтра в Python можно использовать функцию len(), вы можете использовать любую из них:

times_fetched = len(Fetch.objects.filter(person=tom))
# Result: 5

Вы можете получить доступ к дому Тома, сделав следующее:

house = tom.house         # House instance
house_name = house.name   # Name of the house

Вы также можете получить количество раз, когда человек из определенного дома был "найден":

house = House.objects.get(id=3) # Guess House ID is 3
times_fetched_from_house = Fetch.objects.filter(person__house=house)

В данном случае он фильтрует по дому с id=3. Это возможно благодаря связи между Person и House (ForeignKey).

Дайте мне знать, если это решит вашу проблему.

Вернуться на верх