No puede crear relaciones m2m a partir de objetos no guardados. Si tienes el pk
s, prueba esto:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
Actualización: Después de leer la respuesta del saverio , decidí investigar el tema un poco más en profundidad. Aquí están mis hallazgos.
Esta fue mi sugerencia original. Funciona, pero no es óptimo. (Nota: estoy usando Bar
s y a en Foo
lugar de User
s y a Sample
, pero entiendes la 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)
Genera un total de 7 consultas:
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)
Estoy seguro de que podemos hacerlo mejor. Puede pasar varios objetos al add()
método:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)
Como podemos ver, pasar varios objetos guarda uno 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)
No sabía que también puedes asignar una lista de objetos:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]
Desafortunadamente, eso crea uno adicional 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)
Intentemos asignar una lista de pk
s, como sugirió saverio:
foo = Foo()
foo.save()
foo.bars = [1,2]
Como no buscamos las dos Bar
s, guardamos dosSELECT
declaraciones, lo que resulta en un total de 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)
Y el ganador es:
foo = Foo()
foo.save()
foo.bars.add(1,2)
Pasar pk
s a add()
nos da un total de 4 consultas:
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)
Para futuros visitantes, puede crear un objeto y todos sus objetos m2m en 2 consultas utilizando el nuevo bulk_create en django 1.4. Tenga en cuenta que esto solo se puede usar si no requiere ningún procesamiento previo o posterior de los datos con métodos o señales save (). Lo que inserte es exactamente lo que estará en el DB
Puede hacer esto sin especificar un modelo "a través" en el campo. Para completar, el siguiente ejemplo crea un modelo de Usuarios en blanco para imitar lo que el cartel original estaba pidiendo.
Ahora, en un shell u otro código, cree 2 usuarios, cree un objeto de muestra y agregue en masa los usuarios a ese objeto de muestra.
fuente
Django 1.9
Un ejemplo rápido:
fuente
RelatedObjectManagers son diferentes "atributos" que los campos en un Modelo. La forma más sencilla de lograr lo que estás buscando es
Es lo mismo que asignar una lista de usuarios, sin las consultas adicionales y la construcción del modelo.
Si el número de consultas es lo que le molesta (en lugar de la simplicidad), entonces la solución óptima requiere tres consultas:
Esto funcionará porque ya sabemos que la lista de 'usuarios' está vacía, por lo que podemos crear sin pensar.
fuente
Puede reemplazar el conjunto de objetos relacionados de esta manera (nuevo en Django 1.9):
fuente
Si alguien está buscando responder a David Marbles en un campo ManyToMany autorreferido. Los identificadores del modelo through se denominan: "to_'model_name_id" y "from_'model_name'_id".
Si eso no funciona, puede verificar la conexión de django.
fuente