Как эффективно получить количество внешних ключей в модели 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).
Дайте мне знать, если это решит вашу проблему.