Django: получать только объекты с максимальным количеством иностранных ключей

Вопрос довольно простой, но, возможно, неразрешимый с помощью Django.

Например, у меня есть модель

class MyModel(models.Model)
   field_a = models.IntegerField()
   field_b = models.CharField()
   field_c = models.ForegnKey(MyOtherModel)

Вопрос в том, как выбрать только объекты, имеющие максимальное количество связей с MyOtherModel и желательно (почти обязательно) только с одним набором запросов?

Допустим, у нас есть 100 записей, 50 шт. указывают на поле_c_id=1, 40 шт. на поле_c_id=2 и остальные 10 шт. записей на поле_c_id=3. Мне нужны только те, которые указывают на поле_c_id=1? Поскольку 50 будет максимальным количеством.

Спасибо...

Ок сначала вам нужно related_name в вашей модели MyModel

в models.py

class MyOtherModel(models.Model)
   field_a = models.IntegerField()


class MyModel(models.Model)
   field_a = models.IntegerField()
   field_b = models.CharField()
   field_c = models.ForeignKey(MyOtherModel, on_delete=models.CASCADE, related_name="my_other_model")

Вы можете получить наиболее используемую модель MyOtherModel

в файле views.py


most_used = MyOtherModel.objects.annotate(my_other_model_count=Count('my_other_model')).order_by('-my_other_model_count')[:1]

введите [:1], если вам нужен 1, если вам нужно больше, вы можете установить любое количество или удалить его

Or

А вот другое решение, которое лучше этого

Сначала мы должны добавить одно поле в вашу MyOtherModel, которое ведет подсчет MyModel

class MyOtherModel(models.Model)
   field_a = models.IntegerField()
   my_model_count = models.IntegerField()

А нам нужно обновлять счетчик при добавлении, обновлении или удалении объекта в MyModel, для этого я рекомендую использовать сигналы django

в вашем models.py

from django.dispatch import receiver
from django.db.models.signals import pre_save, pre_delete


#at the bottom of your model

@receiver(pre_save, sender=MyModel)
def products_reputation_count(sender, instance, *args, **kwargs):
    if instance.pk:
        old_instance = MyOtherModel.objects.get(id=instance.pk)
        old_instance.reputation.product_count -= 1
        instance.reputation.product_count += 1
    else:
        instance.reputation.product_count += 1


@receiver(pre_save, sender= MyModel)
def products_reputation_count(sender, instance, *args, **kwargs):
    instance.reputation.product_count += 1

и в вашем файле views.py

most_used = MyOtherModel.objects.order_by("-my_model_count")[:1]

Думаю, это будет полезно. Если у вас есть какие-либо вопросы, связанные с этим ответом, не стесняйтесь спрашивать больше. Хорошего дня.

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