Невозможно создать отношения m2m из несохраненных объектов. Если у вас есть pk
s, попробуйте следующее:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
Обновление: прочитав ответ saverio , я решил изучить проблему более подробно. Вот мои выводы.
Это было мое первоначальное предложение. Это работает, но не оптимально. (Примечание: я использую Bar
s и a Foo
вместо User
s и a Sample
, но вы поняли идею).
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)
Всего он генерирует 7 запросов:
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
Я уверен, что у нас получится лучше. Вы можете передать add()
методу несколько объектов :
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)
Как мы видим, передача нескольких объектов сохраняет один SELECT
:
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
Я не знал, что вы также можете назначить список объектов:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]
К сожалению, это создает еще одно SELECT
:
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
Попробуем назначить список pk
s, как предлагает saverio:
foo = Foo()
foo.save()
foo.bars = [1,2]
Поскольку мы не получаем два Bar
s, мы сохраняем два SELECT
оператора, в результате чего получается 5:
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
И победителем становится:
foo = Foo()
foo.save()
foo.bars.add(1,2)
Передача pk
s в add()
дает нам 4 запроса:
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
Для будущих посетителей вы можете создать объект и все его объекты m2m за 2 запроса, используя новый bulk_create в django 1.4. Обратите внимание, что это можно использовать только в том случае, если вам не требуется никакой предварительной или последующей обработки данных с помощью методов или сигналов save (). То, что вы вставляете, - это именно то, что будет в БД
Вы можете сделать это без указания «сквозной» модели в поле. Для полноты изложения в приведенном ниже примере создается пустая модель «Пользователи», имитирующая то, что просил исходный плакат.
from django.db import models class Users(models.Model): pass class Sample(models.Model): users = models.ManyToManyField(Users)
Теперь в оболочке или другом коде создайте двух пользователей, создайте образец объекта и массово добавьте пользователей к этому образцу объекта.
Users().save() Users().save() # Access the through model directly ThroughModel = Sample.users.through users = Users.objects.filter(pk__in=[1,2]) sample_object = Sample() sample_object.save() ThroughModel.objects.bulk_create([ ThroughModel(users_id=users[0].pk, sample_id=sample_object.pk), ThroughModel(users_id=users[1].pk, sample_id=sample_object.pk) ])
источник
Django 1.9
Быстрый пример:
источник
RelatedObjectManager - это разные «атрибуты», чем поля в Модели. Самый простой способ добиться того, что вы ищете, - это
sample_object = Sample.objects.create() sample_object.users = [1, 2]
Это то же самое, что и назначение списка пользователей, без дополнительных запросов и построения модели.
Если вас беспокоит количество запросов (а не простота), то оптимальное решение требует трех запросов:
sample_object = Sample.objects.create() sample_id = sample_object.id sample_object.users.through.objects.create(user_id=1, sample_id=sample_id) sample_object.users.through.objects.create(user_id=2, sample_id=sample_id)
Это будет работать, потому что мы уже знаем, что список «пользователей» пуст, поэтому мы можем создавать бездумно.
источник
Вы можете заменить набор связанных объектов следующим образом (новое в Django 1.9):
источник
Если кто-то хочет заняться Дэвидом Марблсом, ответьте на саморегулирующееся поле ManyToMany. Идентификаторы сквозной модели называются: "to_'model_name_id" и "from_'model_name'_id".
Если это не сработает, вы можете проверить соединение django.
источник