Как создать объект для модели Django с полем "многие ко многим"?



моя модель ->



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


Я хочу сделать это (спасти пользователей user1 и user2 в этой модели ) ->



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


Я знаю, что это неправильно: D, но я уверен, что вы получите то, что я хочу do...so как бы вы это сделали ?

1166   5  

5 ответов:

вы не можете создать отношения m2m из несохраненных объектов. Если у вас есть pks, попробуйте это:

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

обновление: после прочтения ответ Саверио, я решил исследовать этот вопрос немного более подробно. Вот мои выводы.

это было мое первоначальное предложение. Это работает, но не является оптимальным. (Примечание: Я использую Barи Foo вместо Userи Sample, а вы получаете идея.)

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

он генерирует колоссальные в общей сложности 7 запросов:

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)

я уверен, что мы можем сделать лучше. Вы можете передать несколько объектов add() способ:

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

как мы видим, передача нескольких объектов экономит один 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)

я не знал, что вы также можете назначить список объектов:

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

к сожалению, это создает один дополнительный 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)

давайте попробуем назначьте список ' pk, как предложил Саверио:

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

как мы не получаем два Bars, Мы спасаем два SELECT заявления, в результате чего в общей сложности 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)

победитель:

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

передает pks, чтобы добавить() дает нам в общей сложности 4 запросы:

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)

для будущих посетителей вы можете создать объект и все его объекты m2m в 2 запросов используя bulk_create в django 1.4. Обратите внимание, что это можно использовать только в том случае, если вам не требуется любой предварительная или постобработка данных с помощью методов или сигналов save (). То, что вы вставляете именно то, что будет в БД

Вы можете сделать это без указания "модель" на поле. Для полноты картины, пример ниже создает пустую модель пользователей, чтобы имитировать то, что просил оригинальный плакат.

from django.db import models

class Users(models.Model):
    pass

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

теперь в оболочке или другом коде создайте 2 пользователя, создайте образец объекта и массово добавьте пользователей в этот образец объекта.

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
Быстрый пример:

sample_object = Sample()
sample_object.save()

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

RelatedObjectManagers-это разные "атрибуты", чем поля в модели. Самый простой способ достичь того, что вы ищете-это

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

это то же самое, что назначить список пользователей, без дополнительных запросов и построения модели.

Если вас беспокоит количество запросов (а не простота), то для оптимального решения требуется три запроса:

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)

это будет работать, потому что мы уже знаем, что список пользователей пуст, поэтому мы можем творить бездумно.

вы можете заменить набор связанных объектов таким образом (новый в Django 1.9):

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

Comments

    Ничего не найдено.