필드가 많거나 많은 Django 모델의 객체를 만드는 방법은 무엇입니까?


138

내 모델 :

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

나는 모두를 저장할 user1user2그 모델 :

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

나는 그것이 틀렸다는 것을 알고 있지만, 내가하고 싶은 것을 얻을 것이라고 확신합니다. 어떻게 하시겠습니까?

답변:


241

저장되지 않은 객체에서 m2m 관계를 작성할 수 없습니다. pks 가 있으면 다음을 시도하십시오.

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

업데이트 : saverio의 답변을 읽은 후에 문제를 좀 더 깊이 조사하기로 결정했습니다. 내 결과는 다음과 같습니다.

이것은 나의 원래 제안이었다. 작동하지만 최적은 아닙니다. (참고 : Bars 및 a Foo대신 Users 및 a를 사용 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)

pksaverio가 제안한대로 s 목록을 할당 해 봅시다 :

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

두 개를 가져 오지 않기 때문에 두 Bar개의 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를 전달 add()하면 총 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)

25
난 당신과 같이 *로 목록을 전달할 수 추가하고 싶습니다 : (* 목록) foo.bars.add과 인수에 목록을 폭발합니다 : D
기예르모 실리카 제품 Trueba

1
ManyToMany에 대한 장고 문서 여야합니다! docs.djangoproject.com/en/1.10/topics/db/examples/many_to_many 또는 docs.djangoproject.com/en/1.10/ref/models/fields 보다 훨씬 명확 하고 포함 된 다른 방법에 대한 성능 저하도 있습니다. 아마 당신은 Django 1.9를 위해 그것을 업데이트 할 수 있습니까? (설정된 방법)
gabn88

하나 이상의 항목과 수량으로 단일 ID로 모델을 저장하고 싶습니다. 가능할까요? class Cart (models.Model) : item = models.ForeignKey (Item, verbose_name = "item") 수량 = models.PositiveIntegerField (default = 1)
Nitesh

와. 놀랍습니다. : D
М.Б.

111

장래 방문자를 위해 django 1.4 의 새로운 bulk_create 를 사용하여 2 개의 쿼리 로 객체와 모든 m2m 객체를 만들 수 있습니다 . 당신이 필요하지 않은 경우이 만 사용할 수 있습니다 어떤 () 메소드 또는 신호 저장과 데이터에 대한 사전 또는 사후 처리를. 당신이 삽입하는 것은 DB에있을 것입니다 정확히

필드에서 "관통"모델을 지정하지 않고도이 작업을 수행 할 수 있습니다. 완성도를 높이기 위해 아래 예는 원본 포스터가 요청한 내용을 모방하는 빈 사용자 모델을 만듭니다.

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)
])

귀하의 답변을 여기 에 사용하려고하는데 멈춰 있습니다. 생각?
Pureferret 2019

명시 적으로 정의 된 중급 (통과) 클래스 없이이 작업을 수행 할 수 있다는 것을 확실히 알고 있지만 중급 클래스를 사용하는 코드 가독성을 권장합니다. 여기를 참조 하십시오 .
colm.anseo

멋진 솔루션!
pymarco

19

장고 1.9
간단한 예 :

sample_object = Sample()
sample_object.save()

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

8

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)

'사용자'목록이 비어 있다는 것을 이미 알고 있으므로 마음대로 만들 수 있습니다.


2

이런 방식으로 관련 객체 세트를 교체 할 수 있습니다 (Django 1.9의 새로운 기능).

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

0

누군가 David Marbles가 자신을 참조하는 ManyToMany 필드에 대답하려고합니다. 관통 모델의 ID를 "to_'model_name_id"및 "from_'model_name'_id"라고합니다.

그래도 작동하지 않으면 장고 연결을 확인할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.