Comment créer un objet pour un modèle Django avec beaucoup de champ?
mon modèle - >
class Sample(models.Model):
users = models.ManyToManyField(User)
je veux faire (enregistrer les utilisateurs, user1 et user2 dans ce modèle ) ->
user1 = User.objects.get(pk=1)
user2 = User.objects.get(pk=2)
sample_object = Sample( users = user1, users=user2 )
sample_object.save()
je sais que c'est mal : D, mais je suis sûr que vous obtenez ce que je veux faire...alors comment feriez-vous ?
5 réponses
vous ne pouvez pas créer des relations m2m à partir d'objets non revêtus. Si vous avez les PK, essayez ceci:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
mise à jour: après avoir lu la réponse de saverio , j'ai décidé d'étudier la question un peu plus en profondeur. Voici mes conclusions.
c'était ma suggestion originale. Il fonctionne, mais n'est pas optimal. (Note: j'utilise Bar
s et un Foo
au lieu de User
s et un 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 impressionnant 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 passer plusieurs objets à la méthode add()
:
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, en passant plusieurs objets 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 n'étais pas au courant que vous pouvez aussi assigner 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 supplémentaire 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', comme saverio suggéré:
foo = Foo()
foo.save()
foo.bars = [1,2]
comme nous ne récupérons pas les deux Bar
s, nous sauvons deux SELECT
déclarations, résultant dans 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)
passant pk
s à ajouter () nous donne un total de 4 questions:
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 dans 2 requêtes en utilisant le nouveau bulk_create dans django 1.4. Notez que ceci n'est utilisable que si vous n'avez pas besoin de n'importe quel pré ou post-traitement sur les données avec les méthodes ou les signaux save (). Ce que vous insérez est exactement ce qui sera dans le DB
Vous pouvez le faire sans spécifier de "travers" modèle sur le champ. Pour être complet, l'exemple ci-dessous crée un modèle D'utilisateur vierge pour imiter ce que l'affiche originale demandait.
from django.db import models
class Users(models.Model):
pass
class Sample(models.Model):
users = models.ManyToManyField(Users)
maintenant, dans un shell ou un autre code, créer 2 utilisateurs, créer un objet échantillon, et en vrac ajouter les utilisateurs à cet objet échantillon.
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)
])
Django 1.9
Un exemple rapide:
sample_object = Sample()
sample_object.save()
list_of_users = DestinationRate.objects.all()
sample_object.users.set(list_of_users)
RelatedObjectManagers sont différents" attributs " que les champs dans un Model. La façon la plus simple d'atteindre ce que vous recherchez est
sample_object = Sample.objects.create()
sample_object.users = [1, 2]
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:
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)
cela marchera parce que nous nous savons déjà que la liste des "utilisateurs" est vide, donc nous pouvons créer sans réfléchir.
vous pourriez remplacer l'ensemble des objets liés de cette façon (nouveau dans Django 1.9):
new_list = [user1, user2, user3]
sample_object.related_set.set(new_list)