เลือกและอัปเดตเรกคอร์ดฐานข้อมูลด้วยแบบสอบถามเดียว


140

ฉันจะเรียกใช้คำสั่งupdateและselectคำสั่งเดียวกันได้อย่างไรquerysetแทนที่จะต้องทำสองแบบสอบถาม: - หนึ่งเพื่อเลือกวัตถุ - และหนึ่งเพื่ออัปเดตวัตถุ

สิ่งที่เทียบเท่าใน SQL จะเป็นดังนี้:

update my_table set field_1 = 'some value' where pk_field = some_value

คำตอบ:


269

ใช้วิธีวัตถุupdate queryset :

MyModel.objects.filter(pk=some_value).update(field1='some value')

96
เพียงแค่คำเตือนที่เป็นธรรม ... หากคุณใช้updateวิธีการเช่นนี้สัญญาณใด ๆ ที่แนบมากับโมเดลนั้นหรือ "สิ่งที่เป็นรหัส" อื่น ๆ จะไม่ทำงานกับวัตถุ เป็นเพียงตัวชี้จากคนที่ถูกเผา :)
DMac the Destroyer

@DMactheDestroyer ขอบคุณสำหรับข้อมูลที่มีค่า แล้วเราควรใช้วิธีการที่เก่ากว่าในการอัปเดตหรือไม่? (เช่น) รับและบันทึก?

@ เรียนรู้ที่ดีทุกอย่างขึ้นอยู่กับสถานการณ์ของคุณ updateเป็นวิธีที่ดีสำหรับการปรับปรุงมวล แต่มันควรจะตั้งค่าออกคำเตือนในหัวของคุณเมื่อคุณใช้มันที่คุณจำเป็นต้องตรวจสอบสัญญาณใด ๆ ที่ติดอยู่กับวัตถุที่อาจจะต้องมีการยิงด้วยตนเอง
dmac พิฆาต

3
เป็นไปได้หรือไม่ที่จะเข้าถึงอินสแตนซ์รุ่นปัจจุบันในฟังก์ชันอัพเดต ชอบMyModel.objects.filter(pk=some_value).update(field1=self.data)
Dipak

8
@DipakChandranP คุณควรถามคำถามใหม่มากกว่าที่จะแสดงความคิดเห็นเกี่ยวกับคำถามอายุหกขวบ แต่นิพจน์ F () อาจเป็นไปได้ว่าคุณต้องการ
Daniel Roseman

70

วัตถุฐานข้อมูล Django ใช้เมธอด save () เดียวกันในการสร้างและเปลี่ยนแปลงวัตถุ

obj = Product.objects.get(pk=pk)
obj.name = "some_new_value"
obj.save()

Django รู้จัก UPDATE กับ INSERT ได้อย่างไร
หากตั้งค่าแอตทริบิวต์คีย์หลักของออบเจ็กต์เป็นค่าที่ประเมินเป็น True (เช่นค่าอื่นที่ไม่ใช่ None หรือสตริงว่าง) Django จะดำเนินการ UPDATE หากไม่ได้ตั้งค่าแอตทริบิวต์คีย์หลักของออบเจ็กต์หรือหากการอัปเดตไม่อัปเดตสิ่งใด Django จะเรียกใช้งาน INSERT

อ้างอิง: https://docs.djangoproject.com/en/1.9/ref/models/instances/


17

คำตอบนี้เปรียบเทียบสองแนวทางข้างต้น หากคุณต้องการอัปเดตวัตถุจำนวนมากในบรรทัดเดียวให้ไปที่:

# Approach 1
MyModel.objects.filter(field1='Computer').update(field2='cool')

มิฉะนั้นคุณจะต้องวนซ้ำชุดแบบสอบถามและอัปเดตแต่ละวัตถุ:

#Approach 2    
objects = MyModel.objects.filter(field1='Computer')
for obj in objects:
    obj.field2 = 'cool'
    obj.save()
  1. Approach 1 เร็วกว่าเพราะสร้างแบบสอบถามฐานข้อมูลเพียงชุดเดียวเมื่อเทียบกับแนวทาง 2 ซึ่งทำให้แบบสอบถามฐานข้อมูล 'n + 1' (สำหรับ n รายการในชุดแบบสอบถาม)

  2. วิธีกำปั้นทำให้แบบสอบถาม db หนึ่งรายการคือ UPDATE อันที่สองทำให้สอง: SELECT แล้ว UPDATE

  3. ข้อเสียคือสมมติว่าคุณมีทริกเกอร์ใด ๆ เช่นการอัปเดตupdated_onหรือฟิลด์ที่เกี่ยวข้องดังกล่าวจะไม่ถูกทริกเกอร์ในการอัปเดตโดยตรงเช่นแนวทางที่ 1

  4. Approach 1 ใช้กับ Queryset ดังนั้นจึงเป็นไปได้ที่จะอัปเดตหลายออบเจ็กต์พร้อมกันไม่ใช่ในกรณีของวิธีการ 2


เกี่ยวกับ 1. - ฉันคิดว่าผลการสืบค้นได้รับการแคชในการโทรครั้งแรกเพื่อสอบถามดังนั้นจึงยังคงมีการเรียกไปยัง DB เพียงครั้งเดียว
user2340939

2

ในบางกรณีserializerคุณสามารถอัปเดตได้อย่างง่ายดาย!

my_model_serializer = MyModelSerializer(
    instance=my_model, data=validated_data)
if my_model_serializer.is_valid():

    my_model_serializer.save()

ในบางกรณีformเท่านั้น!

instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
    form.save()

ฉันคิดว่า serializers มาจาก Djanog Rest Framework และไม่ใช่ Django ที่เหมาะสม
Code-Apprentice

1
ใช่อย่างไรก็ตามDjango formมาจาก Django Proper
Jamil Noyda
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.