私のモデル:
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()
私はそれが間違っていることを知っていますが、あなたは私がやりたいことを手に入れると確信しています。どうしますか?
未保存のオブジェクトからm2mリレーションを作成することはできません。 pk
sがある場合は、これを試してください:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
更新:saverio's answer を読んだ後、この問題をもう少し詳しく調査することにしました。これが私の発見です。
これは私の最初の提案でした。動作しますが、最適ではありません。 (注:Bar
sとFoo
の代わりにUser
sと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)
ご覧のとおり、複数のオブジェクトを渡すと、1つの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]
残念ながら、それは1つの追加の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)
Saverioが示唆したように、pk
sのリストを割り当てましょう:
foo = Foo()
foo.save()
foo.bars = [1,2]
2つのBar
をフェッチしないので、2つの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)
将来の訪問者のために、Djangoの新しいbulk_createを使用して、オブジェクトとそのすべてのm2mオブジェクトを2クエリで作成できます。 _ 1.4。これは、save()メソッドまたはシグナルを使用して、データのany前処理または後処理を必要としない場合にのみ使用できることに注意してください。挿入するのは、まさにDBにあるものです
これは、フィールドで「スルー」モデルを指定せずに実行できます。完全を期すために、以下の例では、空のユーザーモデルを作成して、元のポスターが求めていたものを模倣します。
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]
これは、追加のクエリとモデル構築なしで、ユーザーリストを割り当てるのと同じです。
クエリの数が(単純化するのではなく)煩わしい場合、最適なソリューションには3つのクエリが必要です。
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)