it-swarm.com.de

Wie erstelle ich ein Objekt für ein Django Modell mit vielen zu vielen Feldern?

Mein Modell:

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

Ich möchte beide speichern user1 und user2 in diesem Modell:

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

Ich weiß, dass das falsch ist, aber ich bin sicher, Sie bekommen, was ich tun möchte. Wie würdest du es machen ?

124
Sai Krishna

Sie können keine m2m-Relationen aus nicht gespeicherten Objekten erstellen. Wenn Sie die pks haben, versuchen Sie dies:

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

Update: Nachdem ich die Antwort von Saverio gelesen hatte, beschloss ich, das Problem etwas genauer zu untersuchen. Hier sind meine Erkenntnisse.

Dies war mein ursprünglicher Vorschlag. Es funktioniert, ist aber nicht optimal. (Hinweis: Ich verwende Bars und Foo anstelle von Users und Sample, aber Sie haben die Idee).

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

Es werden insgesamt 7 Abfragen generiert:

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)

Ich bin sicher, wir können es besser machen. Sie können der add() -Methode mehrere Objekte übergeben:

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

Wie wir sehen können, speichert das Übergeben mehrerer Objekte ein 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)

Mir war nicht bewusst, dass Sie auch eine Liste von Objekten zuweisen können:

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

Leider entsteht dadurch ein weiteres 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)

Versuchen wir, eine Liste von pks zuzuweisen, wie von saverio vorgeschlagen:

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

Da wir die beiden Bars nicht abrufen, speichern wir zwei SELECT -Anweisungen, was insgesamt 5 ergibt:

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)

Und der Gewinner ist:

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

Wenn Sie pks an add() übergeben, erhalten Sie insgesamt 4 Abfragen:

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)
217
Daniel Hepper

Für zukünftige Besucher können Sie ein Objekt und alle seine m2m-Objekte in 2 Abfragen mit dem neuen - erstellen. bulk_create in Django 1.4. Beachten Sie, dass dies nur verwendet werden kann, wenn Sie nicht any benötigen Vor- oder Nachbearbeitung der Daten mit save () Methoden oder Signalen. Was Sie einfügen, ist genau das, was in der DB sein wird

Sie können dies tun, ohne ein "Durch" -Modell auf dem Feld anzugeben. Der Vollständigkeit halber wird im folgenden Beispiel ein leeres Benutzermodell erstellt, um die Frage des ursprünglichen Posters nachzuahmen.

from Django.db import models

class Users(models.Model):
    pass

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

Erstellen Sie nun in einer Shell oder einem anderen Code zwei Benutzer, erstellen Sie ein Beispielobjekt, und fügen Sie die Benutzer diesem Beispielobjekt als Bulk-Datei hinzu.

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)
])
98
David Marble

Django 1.9
Ein kurzes Beispiel:

sample_object = Sample()
sample_object.save()

list_of_users = DestinationRate.objects.all()
sample_object.users.set(list_of_users)
16
Slipstream

RelatedObjectManager sind andere "Attribute" als Felder in einem Modell. Der einfachste Weg, um das zu erreichen, wonach Sie suchen, ist

sample_object = Sample.objects.create()
sample_object.users = [1, 2]

Das ist dasselbe wie das Zuweisen einer Benutzerliste, ohne die zusätzlichen Abfragen und das Erstellen des Modells.

Wenn die Anzahl der Abfragen Sie stört (anstatt der Einfachheit), sind für die optimale Lösung drei Abfragen erforderlich:

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)

Dies wird funktionieren, da wir bereits wissen, dass die Benutzerliste leer ist, sodass wir sinnlos erstellen können.

8
rewritten

Sie können den Satz verwandter Objekte auf diese Weise ersetzen (neu in Django 1.9):

new_list = [user1, user2, user3]
sample_object.related_set.set(new_list)
1
iraj jelodari