我的模特:
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()
我知道这是错的,但我相信你会得到我想做的事。你会怎么做?
答案 0 :(得分:210)
您无法从未保存的对象创建m2m关系。如果你有pks,试试这个:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
更新:在阅读saverio's answer后,我决定更深入地研究这个问题。以下是我的发现。
这是我最初的建议。它有效,但不是最佳的。 (注意:我使用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的列表,如saverio建议的那样:
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)
答案 1 :(得分:93)
对于将来的访问者,您可以使用django 1.4中的新 bulk_create 在 2个查询中创建一个对象及其所有m2m对象。请注意,只有在使用save()方法或信号对数据进行任何预处理或后处理时,才可以使用此选项。您插入的内容正是数据库中的内容
您可以在不指定字段上的“直通”模型的情况下执行此操作。为了完整起见,下面的示例创建了一个空白的用户模型,以模仿原始海报的要求。
from django.db import models
class Users(models.Model):
pass
class Sample(models.Model):
users = models.ManyToManyField(Users)
现在,在shell或其他代码中,创建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)
])
答案 2 :(得分:14)
Django 1.9
一个简单的例子:
$(document).ready(function(){
$('.button').click(function () {
$(this).parent().parent().find('.a').css('font-weight', 'bold');
});
});
答案 3 :(得分:7)
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)
这样做是有效的,因为我们已经知道'用户'列表是空的,所以我们可以盲目地创建。
答案 4 :(得分:1)
您可以用这种方式替换相关对象集(Django 1.9中的新内容):
new_list = [user1, user2, user3]
sample_object.related_set.set(new_list)
答案 5 :(得分:-1)
如果某人正在寻找David Marbles,那么他会在引用ManyToMany字段的自我上回答。通过模型的ID称为: “ to_'model_name_id”和 “ from_'model_name'_id”。
如果这不起作用,您可以检查Django连接。