एक Django मॉडल के लिए एक ऑब्जेक्ट को कई फ़ील्ड के साथ कैसे बनाएं?


138

मेरा मॉडल:

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

मुझे पता है कि यह गलत है, लेकिन मुझे यकीन है कि आपको वही मिलेगा जो मैं करना चाहता हूं। आपको इसे कैसे करना होगा ?

जवाबों:


241

आप सहेजे गए ऑब्जेक्ट से m2m संबंध नहीं बना सकते। यदि आपके पास pkएस है, तो यह कोशिश करें:

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रूप में saverio का सुझाव दिया है, एस की एक सूची आवंटित करने की कोशिश करते हैं :

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)

पासिंग pkके लिए रों 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
Guillermo Siliceo Trueba

1
यह कईToMany के बारे में Django डॉक्स होना चाहिए! बहुत स्पष्ट है तो 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

मैं सिंगल आइडी के साथ मॉडल को फिर एक आइटम और मात्रा के साथ सहेजना चाहता हूं। क्या यह संभव होगा ?? क्लास कार्ट (मॉडल। मॉडल): आइटम = मॉडल। फ़ॉरइनकेके (आइटम, वर्बोज़_नाम = "आइटम") मात्रा = मॉडल। पॉसिटिवइंटरफ़िल्ड (डिफ़ॉल्ट = 1)
नितेश '’

वाह। मैं चकित हूँ। : D
М.Б.

111

भविष्य के आगंतुकों के लिए, आप django 1.4 में नए बल्क_क्रिएट का उपयोग करके 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)
])

मैं यहां आपके उत्तर का उपयोग करने की कोशिश कर रहा हूं लेकिन मैं फंस रहा हूं। विचार?
16

यह निश्चित रूप से जानकारीपूर्ण है कि एक स्पष्ट रूप से परिभाषित इंटरमीडिएट (थ्रू) वर्ग के बिना यह कर सकते हैं, हालांकि, इंटरमीडिएट कक्षा का उपयोग करके कोड पठनीयता के लिए सिफारिश की जाती है। देखें यहाँ
colm.anseo

भयानक समाधान!
pymarco


8

संबंधितऑब्जेक्ट प्रबंधक एक मॉडल में फ़ील्ड की तुलना में अलग-अलग "विशेषता" हैं। आप जो खोज रहे हैं उसे हासिल करने का सबसे सरल तरीका है

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

यदि कोई व्यक्ति डेविड मार्बल्स का जवाब देना चाहता है, तो वह कईToMany क्षेत्र का संदर्भ देता है। थ्रू मॉडल के आईडी को कहा जाता है: "to_'model_name_id" और "from_'model_name'_id"।

अगर वह काम नहीं करता है तो आप django कनेक्शन की जांच कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.