วิธีการเพิ่มหลายวัตถุในความสัมพันธ์ ManyToMany ในครั้งเดียวใน Django?


185

จาก Django doc ฉันควรจะสามารถส่งวัตถุหลายรายการพร้อมกันเพื่อเพิ่มความสัมพันธ์หลายอย่าง แต่ฉันได้รับ

* TypeError: ประเภท unhashable: 'รายการ'

เมื่อฉันพยายามที่จะผ่านชุดแบบสอบถาม django casted ในรายการ ผ่าน Queryset หรือ ValuesListQueryset ดูเหมือนว่าจะล้มเหลว มีวิธีที่ดีกว่าใช้สำหรับลูปหรือไม่?

คำตอบ:


320

ใช้: object.m2mfield.add(*items)ตามที่อธิบายไว้ในเอกสารประกอบ :

add() ยอมรับจำนวนข้อโต้แย้งโดยพลการไม่ใช่รายการของอาร์กิวเมนต์

add(obj1, obj2, obj3, ...)

หากต้องการขยายรายการนั้นไปยังอาร์กิวเมนต์ให้ใช้ *

add(*[obj1, obj2, obj3])

ภาคผนวก:

Django ไม่ได้เรียกobj.save()แต่ละรายการ แต่ใช้bulk_create()แทน


ถ้าคุณดูที่ผู้จัดการมันจะทำการวนรอบวัตถุและการโทรที่บันทึกไว้
Sam Dolan

3
การทดสอบสั้น ๆ จากเปลือกแสดงให้เห็นว่า @sdolan เป็นจริง (ปัจจุบัน) ไม่ถูกต้อง คือเมื่อฉันดู SQL ที่สร้างฉันเห็นเพียงคำสั่งแทรกเดียว: INSERT INTO app_one_twos (one_id, two_id) ค่า (1, 1), (1, 2), (1, 3), (1, 4); นี่คือใน Django 1.4
Klaas van Schelven

@ KlaasvanSchelven: ฉันจำไม่ได้ว่าทดสอบผ่าน sql ที่สร้างขึ้น แต่จากความคิดเห็นของฉันฉันค่อนข้างแน่ใจว่าฉันเพิ่งดูที่ซอร์สโค้ด โปรดทราบว่านี่เป็นเวลากว่า 2 ปีที่ผ่านมาดังนั้นฉันหวังว่าสิ่งต่าง ๆ จะได้รับการปรับปรุงให้ดีขึ้นเล็กน้อย
Sam Dolan

1
@sdolan ไม่พวกเขายังไม่ได้ปรับปรุง ฉันแค่ทดสอบมัน
Saransh Mohapatra

1
มีวิธีใดในการทำเช่นนี้โดยใช้ค่า (เช่น id) บางครั้งคุณไม่มีรายการวัตถุ แต่รายการค่าวัตถุ (เช่น id) แทนที่จะวนลูปผ่านและหยิบวัตถุทั้งหมดเข้าสู่รายการอื่น ...
DannyMoshe

48

หากต้องการเพิ่มในหากคุณต้องการเพิ่มพวกเขาจากชุดแบบสอบถาม

ตัวอย่าง

# Returns a queryset
permissions = Permission.objects.all()

# Add the results to the many to many field (notice the *)

group = MyGroup.objects.get(name='test')

group.permissions.add(*permissions)

จาก: แทรกผลลัพธ์ชุดแบบสอบถามลงใน ManytoManyfield


3
สิ่งนี้ทำสองคำสั่งแทนหนึ่ง :(
DylanYoung

2
โปรดทราบว่าคุณไม่จำเป็นต้องเปลี่ยนเป็นรายการ เพียงเพิ่ม (* การอนุญาต) โดยตรง
BjornW

34

Django 1.9 เพิ่มวิธีเพิ่มเติมสำหรับการเพิ่มความสัมพันธ์แบบหลายต่อหลายคน

เอกสารประกอบ: https://docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.set

set เป็นความดีใหม่:

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)

2
setฉันคิดเสมอ มันเป็นเพียงแค่ว่ามันใช้ในการทำงานที่ผ่านการมอบหมายe.related_set = new_listในเก่า Djangos e.related_set.set(new_list)เทียบเท่ากับ พวกเขาเพิ่งรู้ว่า "ชัดเจนดีกว่าโดยนัย"
DylanYoung

1
ข้อควรระวัง: เพื่อให้กระชับตั้งค่าลบรุ่นที่เกี่ยวข้องที่มีอยู่ทั้งหมด ดังนั้นหากคุณต้องการเพิ่มรายชื่อของวัตถุใหม่และต้องการที่จะให้มีอยู่เหมือนเดิมใช้เพิ่ม (* newlist)
Tasawar ฮุสเซน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.