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]
Думаю, это будет полезно. Если у вас есть какие-либо вопросы, связанные с этим ответом, не стесняйтесь спрашивать больше. Хорошего дня.