如何为具有多对多字段的Django模型创建对象? [英] How to create an object for a Django model with a many to many field?

查看:134
本文介绍了如何为具有多对多字段的Django模型创建对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的模型 - >

  class Sample(models.Model):
users = models.ManyToManyField )

我想这样做(在这个模型中保存用户,user1和user2) - >

  user1 = User.objects.get(pk = 1)
user2 = User.objects.get(pk = 2)
sample_object = Sample(users = user1,users = user2)
sample_object.save()


$ b $我知道这是错的:D,但我相信你会得到我想做的事情,所以你怎么做?

解决方案

无法从未保存的对象创建m2m关系。如果你有pks,请尝试:

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

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



这是我原来的建议。它有效,但不是最佳的。 (注意:我使用和一个 Foo 而不是用户 s和一个样本,但你会得到想法)。

  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个查询:

  SELECTapp_bar。id,app_bar FROMapp_barWHEREapp_bar。id= 1 
SELECTapp_bar。id,app_bar。nameFROMapp_barWHEREapp_bar。id= 2
INSERT INTOapp_foo(name)VALUES()
SELECTapp_foo_bars。bar_idFROMapp_foo_barsWHERE(app_foo_bars。foo_id= 1 ANDapp_foo_bars。bar_id IN(1))
INSERT INTOapp_foo_bars(foo_id,bar_id)VALUES(1,1)
SELECTapp_foo_barsbar_idFROMapp_foo_barsWHERE(app_foo_bars foo_id= 1 ANDapp_foo_bars。bar_idIN(2))
INSERT INTOapp_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)

如我们所见,传递多个对象可以节省一个code> SELECT :

  SELECTapp_bar。id,app_bar nameFROMapp_barWHEREapp_bar。id= 1 
SELECTapp_bar。id,app_bar。nameFROMapp_barWHEREapp_barid= 2
INSERT INTOapp_foo(name)VALUES()
SELECTapp_foo_barsbar_idFROMapp_foo_barsWHERE(app_foo_bars。foo_id= 1 ANDapp_foo_bars。 bar_idIN(1,2))
INSERT INTOapp_foo_bars(foo_id,bar_id)VALUES(1,1)
INSERT INTOapp_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]
pre>

不幸的是,创建一个额外的 SELECT



< 从app_barWHEREapp_bar。id= 1
SELECTapp_bar。 id,app_bar。nameFROMapp_barWHEREapp_bar。id= 2
INSERT INTOapp_foo(name)VALUES()
SELECTapp_foo_bars 。id,app_foo_bars。foo_id,app_foo_bars。bar_idFROMapp_foo_barsWHEREapp_foo_barsfoo_id= 1
SELECTapp_foo_barsbar_idFROMapp_foo_bars WHERE(app_foo_bars。foo_id= 1 ANDapp_foo_bars。bar_idIN(1,2))
INSERT INTOapp_foo_bars(foo_id,bar_id)VALUES(1,1)
INSERT INTOapp_foo_bars(foo_id,bar_id)VALUES(1,2)



  foo = Foo()
我们尝试分配一个'pk'的列表, foo.save()
foo.bars = [1,2]

由于我们没有获取两个 Bar s,所以我们保存两个 SELECT 语句,导致总共5:

  INSERT INTOapp_foo(name)VALUES() 
SELECTapp_foo_barsid,app_foo_barsfoo_id,app_foo_barsbar_idFROMapp_foo_barsWHEREapp_foo_barsfoo_id= 1
SELECTapp_foo_bars 。bar_idFROMapp_foo_barsWHERE(app_foo_bars。foo_id= 1 ANDapp_foo_bars。bar_idIN(1,2))
INSERT INTOapp_foo_bars(foo_id,bar_id )VALUES(1,1)
INSERT INTOapp_foo_bars(foo_id,bar_id)VALUES(1,2)

获胜者是:

  foo = Foo()
foo .save()
foo.bars.add(1,2)

传递 pk s to add()给我们总共4个查询:

  INSERT INTOapp_foo(name)VALUES()
SELECTapp_foo_barsbar_idFROMapp_foo_barsWHERE(app_foo_bars。foo_id= 1 ANDa pp_foo_barsbar_idIN(1,2))
INSERT INTOapp_foo_bars(foo_id,bar_id)VALUES(1,1)
INSERT INTOapp_foo_bars(foo_id ,bar_id)VALUES(1,2)


My model ->

class Sample(models.Model):
     users = models.ManyToManyField(User)

I want to do this (save users, user1 and user2 in this model ) ->

user1 = User.objects.get(pk=1)
user2 = User.objects.get(pk=2)
sample_object = Sample( users = user1, users=user2 )
sample_object.save()

I know that's wrong : D, but I'm sure you get what I want to do...so how would you do it ?

解决方案

You cannot create m2m relations from unsaved objects. If you have the pks, try this:

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

Update: After reading the saverio's answer, I decided to investigate the issue a bit more in depth. Here are my findings.

This was my original suggestion. It works, but isn't optimal. (Note: I'm using Bars and a Foo instead of Users and a Sample, but you get the idea).

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)

It generates a whopping total of 7 queries:

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)

I'm sure we can do better. You can pass multiple objects to the add() method:

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)

As we can see, passing multiple objects saves one 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)

I wasn't aware that you can also assign a list of objects:

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]

Unfortunately, that creates one additional 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)

Let's try to assign a list of `pk's, as saverio suggested:

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

As we don't fetch the two Bars, we save two SELECT statements, resulting in a total of 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)

And the winner is:

foo = Foo()
foo.save()
foo.bars.add(1,2)

Passing pks to add() gives us a total of 4 queries:

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模型创建对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆