Як додати декілька об’єктів у відносини ManyToMany відразу в Django?


185

Виходячи з документа Django, я повинен мати можливість передавати відразу декілька об'єктів, щоб бути доданими до багатьохзалежних відносин, але я отримую

* TypeError: unhashable type: 'list'

коли я намагаюся передати набір запитів про джанго, перелічені у списку. Здається, також проходить набір запитів або ValuesListQueryset. Чи є кращий спосіб, ніж використовувати цикл?

Відповіді:


320

Використання: object.m2mfield.add(*items)як описано в документації :

add() приймає довільну кількість аргументів, а не їх перелік.

add(obj1, obj2, obj3, ...)

Щоб розгорнути цей список на аргументи, використовуйте *

add(*[obj1, obj2, obj3])

Додаток:

Django не дзвонить obj.save()по кожному пункту, а використовує bulk_create()натомість.


Якщо ви подивитеся на менеджера, він просто робить цикл для об'єктів і викликає збереження на них.
Сем Долан

3
Короткий експеримент із оболонки показує, що @sdolan насправді (на даний момент) неправильний. Тобто, коли я дивлюся на згенерований SQL, я бачу лише одне вкладене твердження: ВСТАВЛЯЙТЕСЬ В ІНТУ app_one_twos (one_id, two_id) VALUES (1, 1), (1, 2), (1, 3), (1, 4); Це в Django 1.4.
Klaas van Schelven

@KlaasvanSchelven: Я не пам'ятаю тестувати це через створений sql, але, виходячи з мого коментаря, я майже впевнений, що я просто поглянув на вихідний код. Майте на увазі, що це було понад 2 роки тому, тому я би сподівався, що все було трохи оптимізовано.
Сем Долан

1
@sdolan Ні, вони цього не покращили. Я тільки тестував це.
Саранш Мохапатра

1
Будь-який спосіб зробити це за значенням (колишній ідентифікатор)? Іноді у вас немає списку об'єктів, а списку значень об’єктів (тобто ідентифікаторів)? Замість того, щоб переглядати та захоплювати всі об’єкти в інший список ...
DannyMoshe

48

Щоб додати, Якщо ви хочете додати їх із набору запитів

Приклад

# Returns a queryset
permissions = Permission.objects.all()

# Add the results to the many to many field (notice the *)

group = MyGroup.objects.get(name='test')

group.permissions.add(*permissions)

Від: Вставте результати запитів у ManytoManyfield


3
Це виконує два запити замість одного :(
DylanYoung

2
Зауважте, що вам не потрібно перетворювати його на список. Просто додайте (* дозволи) безпосередньо.
BjornW

34

Django 1.9 додає додаткові способи додати відносини "багато до багатьох".

Документація: https://docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.set

set це нова вигода:

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)

2
setя завжди був там, я думаю. Просто те, що раніше працювали через завдання e.related_set = new_listу старших Джангосі, рівнозначно e.related_set.set(new_list). Вони просто зрозуміли, що "явне краще, ніж неявне".
DylanYoung

1
Обережно: щоб бути стислим, встановіть, щоб видалити всі існуючі пов'язані моделі. Тож якщо ви хочете додати список нових об’єктів і хочете зберегти існуючий недоторканим, використовуйте add (* newlist)
Tasawar Hussain
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.