Você não pode criar relações m2m a partir de objetos não salvos. Se você possui pk
s, tente o seguinte:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
Atualização: Depois de ler a resposta do saverio , decidi investigar o problema um pouco mais profundamente. Aqui estão minhas descobertas.
Esta foi a minha sugestão original. Funciona, mas não é o ideal. (Nota: estou usando Bar
s e a em Foo
vez de User
s e a Sample
, mas você entendeu).
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)
Ele gera um total impressionante 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)
Tenho certeza que podemos fazer melhor. Você pode passar vários objetos para o 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, passar vários objetos salva um 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)
Eu não sabia que você também pode atribuir uma lista de objetos:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]
Infelizmente, isso cria um 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)
Vamos tentar atribuir uma lista de pk
s, como sugerido pela saverio:
foo = Foo()
foo.save()
foo.bars = [1,2]
Como não buscamos os dois Bar
s, salvamos duas SELECT
instruções, resultando em um 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)
E o vencedor é:
foo = Foo()
foo.save()
foo.bars.add(1,2)
Passar pk
s para add()
nos dá um 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, você pode criar um objeto e todos os seus objetos m2m em 2 consultas usando o novo bulk_create no django 1.4. Observe que isso só é utilizável se você não precisar de nenhum pré ou pós-processamento nos dados com métodos ou sinais save (). O que você insere é exatamente o que estará no banco de dados
Você pode fazer isso sem especificar um modelo "através" no campo. Para ser completo, o exemplo abaixo cria um modelo de Usuários em branco para imitar o que o pôster original estava perguntando.
Agora, em um shell ou outro código, crie 2 usuários, crie um objeto de amostra e adicione os usuários em massa a esse objeto de amostra.
fonte
Django 1.9
Um exemplo rápido:
fonte
RelatedObjectManagers são "atributos" diferentes dos campos em um Modelo. A maneira mais simples de alcançar o que você está procurando é
É o mesmo que atribuir uma lista de usuários, sem as consultas adicionais e a construção do modelo.
Se o número de consultas é o que o incomoda (em vez da simplicidade), a solução ideal exige três consultas:
Isso funcionará porque já sabemos que a lista de 'usuários' está vazia, para que possamos criar sem pensar.
fonte
Você pode substituir o conjunto de objetos relacionados desta maneira (novo no Django 1.9):
fonte
Se alguém quer fazer David Marbles, responda por um campo ManyToMany auto-referente. Os IDs do modelo through são chamados: "to_'model_name_id" e "from_'model_name'_id".
Se isso não funcionar, você pode verificar a conexão do django.
fonte