Как создать объект для модели Django с полем "многие ко многим"?
моя модель ->
class Sample(models.Model):
users = models.ManyToManyField(User)
Я хочу сделать это (спасти пользователей user1 и user2 в этой модели ) ->
user1 = User.objects.get(pk=1)
user2 = User.objects.get(pk=2)
sample_object = Sample( users = user1, users=user2 )
sample_object.save()
Я знаю, что это неправильно: D, но я уверен, что вы получите то, что я хочу do...so как бы вы это сделали ?
5 ответов:
вы не можете создать отношения m2m из несохраненных объектов. Если у вас есть pks, попробуйте это:
sample_object = Sample() sample_object.save() sample_object.users.add(1,2)обновление: после прочтения ответ Саверио, я решил исследовать этот вопрос немного более подробно. Вот мои выводы.
это было мое первоначальное предложение. Это работает, но не является оптимальным. (Примечание: Я использую
BarиFooвместоUserи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, как предложил Саверио:
foo = Foo() foo.save() foo.bars = [1,2]как мы не получаем два
Bars, Мы спасаем два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)передает
pks, чтобы добавить() дает нам в общей сложности 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)теперь в оболочке или другом коде создайте 2 пользователя, создайте образец объекта и массово добавьте пользователей в этот образец объекта.
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
Быстрый пример:sample_object = Sample() sample_object.save() list_of_users = DestinationRate.objects.all() sample_object.users.set(list_of_users)
RelatedObjectManagers-это разные "атрибуты", чем поля в модели. Самый простой способ достичь того, что вы ищете-это
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):
new_list = [user1, user2, user3] sample_object.related_set.set(new_list)
Comments