У меня отношения многие-ко-многим.
class Module(BaseModel):
name = models.TextField(unique=True, null=False)
groups = models.ManyToManyField(ModuleGroup, db_table='module_group_members')
class ModuleGroup(BaseModel):
name = models.TextField(unique=True, null=False)
Я хочу получить список модулей и связанных с ними групп, примерно так:
{[
{
'name' : 'name1'
'groups' : ['group1', 'group2']
},
'name' : 'name2'
'groups' : ['group6', 'group7']
}
]}
Пробовал это:
modules = Module.objects.filter(is_active=True)
print('values_list', list(modules.values('name', 'groups')))
Что дает е:
[{'name': 'name1', 'groups__name': 'group2'}, {'name': 'name1', 'groups__name': 'group2'}, {'name': 'name2', 'groups__name': 'group6'}, {'name': 'name2', 'groups__name': 'group7'}, ]
Есть ли способ сгруппировать одни и те же модули вместе, чтобы имена групп были в списке?
from collections import defaultdict
modules = Module.objects.filter(is_active=True)
# We'll need an intermediary for data transformation
# defaultdict is a good choice because then there's no worry about instantiating new list objects for each new key that is encountered
modules_dict = defaultdict(list)
# Add each group to the list of whatever name it belongs to
for module in modules:
modules_dict[module['name']].append(module['groups__name'])
# modules_dict will by now look something like:
'''
{
name1: [group1, group2]
}
'''
# So now it's just a matter of formatting the data structure to your liking
print([{'name': name, 'groups': groups} for name, groups in modules_dict.items()])
прежде всего
from django.db import models
from django.db.models import Prefetch
class ModuleGroup(models.Model):
name = models.TextField(unique=True, null=False)
class Module(models.Model):
name = models.TextField(unique=True, null=False)
groups = models.ManyToManyField(ModuleGroup, db_table='module_group_members')
is_active = models.BooleanField(default=True) # Assuming you have this field in your model
from yourapp.models import Module, ModuleGroup
# Create some ModuleGroup instances
group1 = ModuleGroup.objects.create(name='group1')
group2 = ModuleGroup.objects.create(name='group2')
group3 = ModuleGroup.objects.create(name='group6')
group4 = ModuleGroup.objects.create(name='group7')
# Create some Module instances and associate them with ModuleGroup instances
module1 = Module.objects.create(name='name1', is_active=True)
module1.groups.add(group1, group2)
module2 = Module.objects.create(name='name2', is_active=True)
module2.groups.add(group3, group4)
# Fetch the modules and prefetch related groups
modules = Module.objects.filter(is_active=True).prefetch_related(
Prefetch('groups', queryset=ModuleGroup.objects.only('name'))
)
# Prepare the desired output format
result = []
for module in modules:
groups = [group.name for group in module.groups.all()]
result.append({
'name': module.name,
'groups': groups
})
если ты распечатаешь список
print(result)
ты должен получить
[{'name': 'name1', 'groups': ['group1', 'group2']}, {'name': 'name2', 'groups': []}]
Спасибо, согласно документации, использование prefetch_related — это метод оптимизации, который помогает уменьшить количество запросов к базе данных и повышает производительность при доступе к связанным объектам в отношениях «многие ко многим» или «один ко многим». Это особенно полезно, когда у вас большой количество записей и хотите избежать проблемы с запросом N+1. Вот визуальное сравнение: • Без prefetch_related: N + 1 запрос (1 запрос для основных объектов + 1 запрос для доступа к каждому связанному объекту) • С prefetch_related: 2 запроса (1 запрос для основных объектов + 1 запрос для всех связанных объектов)
Когда вы получаете доступ к связанным объектам без использования prefetch_related. В этом случае, если у вас 10 модулей, Django выполнит 11 запросов: 1 запрос для получения модулей и 1 запрос для каждого модуля для получения связанных с ним групп. И когда вы используете prefetch_related. В этом случае Django выполнит только 2 запроса: 1 запрос для получения модулей и 1 запрос для одновременного получения всех связанных групп. Это значительно уменьшает количество запросов и повышает производительность. Надеюсь, это ответит на ваш вопрос, мистер Питер.
Спасибо, но какова цель предварительной выборки? Я думал, что наличие связи «многие ко многим» уже приведет к поступлению информации ModuleGroup?