Vous ne pouvez pas créer de relations m2m à partir d'objets non enregistrés. Si vous avez le pk
s, essayez ceci:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
Mise à jour: après avoir lu la réponse du saverio , j'ai décidé d'étudier le problème un peu plus en profondeur. Voici mes conclusions.
C'était ma suggestion originale. Cela fonctionne, mais n'est pas optimal. (Remarque: j'utilise Bar
s et a Foo
au lieu de User
s et a Sample
, mais vous voyez l'idée).
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)
Il génère un total énorme de 7 requêtes:
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)
Je suis sûr que nous pouvons faire mieux. Vous pouvez transmettre plusieurs objets à la add()
méthode:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)
Comme nous pouvons le voir, passer plusieurs objets en sauve un 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)
Je ne savais pas que vous pouvez également attribuer une liste d'objets:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]
Malheureusement, cela crée un autre 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)
Essayons d'attribuer une liste de pk
s, comme l'a suggéré saverio:
foo = Foo()
foo.save()
foo.bars = [1,2]
Comme nous ne récupérons pas les deux Bar
s, nous sauvegardons deux SELECT
instructions, ce qui donne 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)
Et le gagnant est:
foo = Foo()
foo.save()
foo.bars.add(1,2)
Passer pk
s à add()
nous donne un total de 4 requêtes:
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)
Pour les futurs visiteurs, vous pouvez créer un objet et tous ses objets m2m en 2 requêtes en utilisant le nouveau bulk_create dans django 1.4. Notez que cela n'est utilisable que si vous n'avez besoin d' aucun pré ou post-traitement des données avec les méthodes ou signaux save (). Ce que vous insérez est exactement ce qui sera dans la base de données
Vous pouvez le faire sans spécifier de modèle «à travers» sur le terrain. Par souci d'exhaustivité, l'exemple ci-dessous crée un modèle d'utilisateurs vierge pour imiter ce que l'affiche originale demandait.
Maintenant, dans un shell ou un autre code, créez 2 utilisateurs, créez un exemple d'objet et ajoutez en bloc les utilisateurs à cet exemple d'objet.
la source
Django 1.9
Un exemple rapide:
la source
Les RelatedObjectManagers sont des «attributs» différents des champs d'un modèle. Le moyen le plus simple d'atteindre ce que vous recherchez est
C'est la même chose que d'attribuer une liste d'utilisateurs, sans les requêtes supplémentaires et la construction du modèle.
Si le nombre de requêtes est ce qui vous dérange (au lieu de la simplicité), alors la solution optimale nécessite trois requêtes:
Cela fonctionnera car nous savons déjà que la liste des «utilisateurs» est vide, nous pouvons donc créer sans réfléchir.
la source
Vous pouvez remplacer l'ensemble des objets associés de cette manière (nouveau dans Django 1.9):
la source
Si quelqu'un cherche à faire David Marbles, répondez sur un champ ManyToMany auto-référencé. Les identifiants du modèle through sont appelés: "to_'model_name_id" et "from_'model_name'_id".
Si cela ne fonctionne pas, vous pouvez vérifier la connexion django.
la source