สร้างวัตถุแบบจำลองจำนวนมากใน django


92

ฉันมีวัตถุมากมายที่ต้องบันทึกในฐานข้อมูลดังนั้นฉันจึงต้องการสร้างอินสแตนซ์ Model ด้วยสิ่งนั้น

ด้วย django ฉันสามารถสร้างอินสแตนซ์โมเดลทั้งหมดด้วยMyModel(data)แล้วฉันต้องการบันทึกทั้งหมด

ตอนนี้ฉันมีบางอย่างเช่นนั้น:

for item in items:
    object = MyModel(name=item.name)
    object.save()

ฉันสงสัยว่าฉันสามารถบันทึกรายการวัตถุได้โดยตรงหรือไม่เช่น:

objects = []
for item in items:
    objects.append(MyModel(name=item.name))
objects.save_all()

จะบันทึกวัตถุทั้งหมดในธุรกรรมเดียวได้อย่างไร?


ดูเหมือนว่าลูกบอลกำลังกลิ้งไปมาเพื่อใช้การแก้ไขสำหรับโค้ด
DanH

1
สงสัยสำหรับ list.save_all? คุณเกือบจะตอบตัวเองได้เพียงแค่ถอดความว่าสงสัยและใช้ 2 คำแรกจากคำถามหัวข้อของคุณ
Sławomir Lenart

คำตอบ:


99

ในการพัฒนา django มีbulk_createวิธีการจัดการอ็อบเจ็กต์ซึ่งใช้เป็นอินพุตอาร์เรย์ของอ็อบเจ็กต์ที่สร้างขึ้นโดยใช้คลาสคอนสตรัคเตอร์ ตรวจสอบ django docs


13
เอกสารของ Django สำหรับbulk_create: docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create
funkotron

1
แต่จำไว้ว่า bulk_create มีข้อ จำกัด บางประการเช่นไม่สร้างคีย์หลักหากเป็นฟิลด์อัตโนมัติที่บันทึก () โดยอัตโนมัติ
Hitesh Garg

@HiteshGarg วันนี้ยังเป็นจริงอยู่ไหม?
Raydel Miranda

1
@RaydelMiranda ใช่มันยังคงเป็นจริง มีอยู่ในเอกสาร:If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does, unless the database backend supports it (currently only PostgreSQL).
interDist

1
ใช้Django 3.0.xและฉันยืนยันว่าการใช้bulk_create()ไม่ทำให้เกิดสัญญาณใด ๆ ฉันสงสัยว่าทำไม.
enchance

43

ใช้bulk_create()วิธีการ เป็นมาตรฐานใน Django ตอนนี้

ตัวอย่าง:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])

1
เปลี่ยนแปลงใน Django 1.10: รองรับการตั้งค่าคีย์หลักบนวัตถุที่สร้างโดยใช้ bulk_create () เมื่อใช้ PostgreSQL ถูกเพิ่ม
elad silver

4

ทำงานให้ฉันใช้การจัดการธุรกรรมด้วยตนเองสำหรับลูป (postgres 9.1):

from django.db import transaction
with transaction.commit_on_success():
    for item in items:
        MyModel.objects.create(name=item.name)

ในความเป็นจริงมันไม่เหมือนกับการแทรกฐานข้อมูลจำนวนมาก แต่จะช่วยให้คุณสามารถหลีกเลี่ยง / ลดขนาดการขนส่ง / การดำเนินการ orms / แบบสอบถาม sql วิเคราะห์ต้นทุน


1
สิ่งนี้เปลี่ยนไปเล็กน้อย ตอนนี้ธุรกรรมไม่มีcommit_on_successอีกต่อไป คุณควรใช้transaction.atomic()See: stackoverflow.com/questions/21861207/…
t_io

4

ต่อไปนี้คือวิธีสร้างเอนทิตีจำนวนมากจากไฟล์ที่คั่นด้วยคอลัมน์โดยเว้นรูทีนที่ไม่มีการอ้างสิทธิ์และไม่หลบหนีทั้งหมด:

SomeModel(Model):
    @classmethod
    def from_file(model, file_obj, headers, delimiter):
        model.objects.bulk_create([
            model(**dict(zip(headers, line.split(delimiter))))
            for line in file_obj],
            batch_size=None)

3

สำหรับการใช้งานบรรทัดเดียวคุณสามารถใช้นิพจน์แลมบ์ดาในแผนที่

map(lambda x:MyModel.objects.get_or_create(name=x), items)

ที่นี่แลมบ์ดาจะจับคู่แต่ละรายการในรายการรายการกับ x และสร้างบันทึกฐานข้อมูลหากจำเป็น

เอกสารแลมด้า


คุณอาจต้องการพูดถึงว่าlambdaต้องก้าวmapข้ามitems:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Manoj Govindan

ใช่นั่นเป็นอีกวิธีหนึ่งที่ฉันพยายามจะพูด (:
FallenAngel

2

การใช้การสร้างจะทำให้เกิดหนึ่งแบบสอบถามต่อรายการใหม่ หากคุณต้องการลดจำนวนการค้นหา INSERT คุณจะต้องใช้อย่างอื่น

ฉันประสบความสำเร็จในการใช้ข้อมูลโค้ดแทรกจำนวนมากแม้ว่าข้อมูลโค้ดจะค่อนข้างเก่า บางทีอาจต้องมีการเปลี่ยนแปลงบางอย่างเพื่อให้ใช้งานได้อีกครั้ง

http://djangosnippets.org/snippets/446/


2

ดูโพสต์บล็อกนี้ในโมดูลBulkops

ในแอป django 1.3 ของฉันฉันได้รับการเร่งความเร็วที่สำคัญ


-20

วิธีที่ง่ายที่สุดคือใช้createเมธอด Manager ซึ่งสร้างและบันทึกวัตถุในขั้นตอนเดียว

for item in items:
    MyModel.objects.create(name=item.name)

+1. หากมีความเป็นเอกลักษณ์และปัจจัยการผลิตที่ซ้ำกันจะเป็นไปได้แล้วมันจะเป็นความคิดที่ดีที่จะใช้name get_or_create
Manoj Govindan

16
สิ่งนี้ตอบคำถามได้อย่างไร? Model.objects.create เทียบเท่ากับ object = MoModel (.. ) object.save () และสิ่งนี้ไม่ได้ทำในธุรกรรมเดียว ...
automagic
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.