ความแตกต่างระหว่างคำอธิบายประกอบของ Django และวิธีการรวม?


115

Django QuerySetมีสองวิธีannotateและaggregate. เอกสารระบุว่า:

ซึ่งแตกต่างจาก aggregate (), annotate () ไม่ใช่ Terminal clause ผลลัพธ์ของอนุประโยค annotate () คือ QuerySet

มีความแตกต่างอื่น ๆ ระหว่างพวกเขาหรือไม่? ถ้าไม่แล้วทำไมถึงaggregateมีอยู่?

คำตอบ:


187

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

การรวมตัว

>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

ส่งคืนพจนานุกรมที่มีราคาเฉลี่ยของหนังสือทั้งหมดในชุดแบบสอบถาม

คำอธิบายประกอบ

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

q เป็นชุดแบบสอบถามของหนังสือ แต่แต่ละเล่มมีการใส่คำอธิบายประกอบด้วยจำนวนผู้แต่ง


ฉันถูกต้องหรือไม่ที่.annotate()qs เพียงอย่างเดียวไม่ได้กด db แต่การโทรq[0].num_authorsทำหรือไม่ ฉันถือว่าaggregateต้องตี db เสมอเนื่องจากเป็น Terminal clause?
นามแฝง 51

@ alias51 ที่เกี่ยวข้องกับคำถามเดิมจริงๆดังนั้นฉันไม่คิดว่าความคิดเห็นเกี่ยวกับคำถามอายุแปดขวบเป็นสถานที่ที่ดีที่สุดในการถาม หากคุณต้องการตรวจสอบเวลาที่การสืบค้นทำงานคุณสามารถตรวจสอบconnection.queriesได้ คำแนะนำ: ตรวจสอบว่าเป็นbook = q[0]หรือ "book.num_authors" ที่ทำให้เกิดการสืบค้น
Alasdair

21

นั่นคือข้อแตกต่างที่สำคัญ แต่การรวมยังทำงานในระดับที่ใหญ่กว่าคำอธิบายประกอบ คำอธิบายประกอบเกี่ยวข้องโดยเนื้อแท้กับแต่ละรายการในชุดแบบสอบถาม หากคุณเรียกใช้Countคำอธิบายประกอบในฟิลด์แบบกลุ่มต่อกลุ่มคุณจะได้รับการนับแยกต่างหากสำหรับสมาชิกแต่ละคนของชุดข้อมูล (เป็นแอตทริบิวต์ที่เพิ่ม) หากคุณจะทำเช่นเดียวกันกับการรวมอย่างไรก็ตามมันจะพยายามนับทุกความสัมพันธ์กับสมาชิกทุกคนของชุดสืบค้นแม้กระทั่งรายการที่ซ้ำกันและส่งคืนค่านั้นเป็นเพียงค่าเดียว


ฉันถูกต้องหรือไม่ที่.annotate()qs เพียงอย่างเดียวไม่ตี db แต่เรียกผลลัพธ์ของคำอธิบายประกอบเช่นq[0].num_authorsdoes? ฉันถือว่าaggregateต้องตี db เสมอเนื่องจากเป็น Terminal clause?
นามแฝง 51

21

Aggregate Aggregate สร้างค่าผลลัพธ์ (สรุป) บน QuerySet ทั้งหมด ผลรวมดำเนินการบน rowset เพื่อรับค่าเดียวจาก rowset (ตัวอย่างเช่นผลรวมของราคาทั้งหมดใน rowset) Aggregate ถูกนำไปใช้กับ QuerySet ทั้งหมดและสร้างค่าผลลัพธ์ (สรุป) ใน QuerySet ทั้งหมด

ในรุ่น:

class Books(models.Model):
    name = models.CharField(max_length=100)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=5, decimal_places=3)

ในเชลล์:

>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column 
>>> {'price__avg': 34.35}

คำอธิบายประกอบคำอธิบาย ประกอบสร้างสรุปอิสระสำหรับแต่ละวัตถุใน QuerySet (เราสามารถพูดได้ว่ามันวนซ้ำแต่ละวัตถุใน QuerySet และใช้การดำเนินการ)

ในรุ่น:

class Video(models.Model):
    name = models.CharField(max_length=52, verbose_name='Name')
    video = models.FileField(upload_to=document_path, verbose_name='Upload 
               video')
    created_by = models.ForeignKey(User, verbose_name='Created by', 
                       related_name="create_%(class)s")
    user_likes = models.ManyToManyField(UserProfile, null=True, 
                  blank=True, help_text='User can like once', 
                         verbose_name='Like by')

ในมุมมอง:

videos = Video.objects.values('id', 'name','video').annotate(Count('user_likes',distinct=True)

ในการดูจะนับจำนวนไลค์สำหรับแต่ละวิดีโอ


เหตุใดจึงdistinct=Trueต้องมีในตัวอย่างสุดท้าย
Yuriy Leonov

@YuriyLeonov แตกต่าง = True ใช้เพื่อให้การดำเนินการดำเนินการกับค่าที่แตกต่างกัน ไม่เกี่ยวข้องกับคำถามปัจจุบันที่ถาม ขออภัยจริงๆที่ฉันใช้รหัสของฉัน
Vinay Kumar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.