如何创build一个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,但我相信你得到了我想要做的事情…那么你会怎么做呢?

您不能从未保存的对象创buildm2m关系。 如果你有pks,试试这个:

 sample_object = Sample() sample_object.save() sample_object.users.add(1,2) 

更新:在阅读saverio的答案之后 ,我决定深入研究这个问题。 这是我的发现。

这是我最初的build议。 它工作,但不是最佳的。 (注意:我使用BarFoo而不是UserSample ,但是你明白了)。

 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] 

不幸的是,这会创build一个额外的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'列表,如saveriobuild议的那样:

 foo = Foo() foo.save() foo.bars = [1,2] 

由于我们不抓取两个Bar ,所以我们保存了两个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到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 1.4中的新bulk_create2个查询中创build一个对象及其所有m2m对象。 请注意,只有在不需要使用save()方法或信号对数据进行任何预处理或后处理的情况下,该function才可用。 你插入的是什么将在数据库中

你可以做到这一点,而不必在该字段中指定“通过”模型。 为了完整起见,下面的示例创build一个空白的用户模型,以模拟原始海报的要求。

 from django.db import models class Users(models.Model): pass class Sample(models.Model): users = models.ManyToManyField(Users) 

现在,在shell或其他代码中,创build2个用户,创build一个示例对象,并将用户批量添加到该示例对象。

 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] 

这与分配用户列表一样,没有额外的查询和模型构build。

如果查询的数量是困扰你的(而不是简单的),那么最佳解决scheme需要三个查询:

 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) 

这将起作用,因为我们已经知道“用户”列表是空的,所以我们可以无意识地创build。

你可以用这种方法replace一组相关的对象(在Django 1.9中是新的):

 new_list = [user1, user2, user3] sample_object.related_set.set(new_list)