เลือก DISTINCT แต่ละคอลัมน์ใน django?


97

ฉันสงสัยว่ามีวิธีใดในการค้นหาใน Django ที่ไม่ใช่ " SELECT * FROM..." ที่อยู่ข้างใต้ ฉันกำลังพยายามทำ " SELECT DISTINCT columnName FROM ..." แทน

โดยเฉพาะฉันมีโมเดลที่ดูเหมือน:

class ProductOrder(models.Model):
   Product  = models.CharField(max_length=20, promary_key=True)
   Category = models.CharField(max_length=30)
   Rank = models.IntegerField()

โดยที่Rankเป็นอันดับภายในCategory. ฉันต้องการที่จะทำซ้ำทุกหมวดหมู่เพื่อดำเนินการบางอย่างกับแต่ละอันดับภายในหมวดหมู่นั้น

ฉันต้องการรับรายการหมวดหมู่ทั้งหมดในระบบก่อนจากนั้นค้นหาผลิตภัณฑ์ทั้งหมดในหมวดหมู่นั้นและทำซ้ำจนกว่าทุกหมวดหมู่จะได้รับการประมวลผล

ฉันควรหลีกเลี่ยง SQL ดิบ แต่ถ้าฉันต้องไปที่นั่นก็ไม่เป็นไร แม้ว่าฉันจะไม่เคยเข้ารหัส SQL ดิบใน Django / Python มาก่อน

คำตอบ:


196

วิธีการหนึ่งที่จะได้รับรายชื่อคอลัมน์ที่แตกต่างจากฐานข้อมูลคือการใช้งานร่วมกับdistinct() values()

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

q = ProductOrder.objects.values('Category').distinct()
print q.query # See for yourself.

# The query would look something like
# SELECT DISTINCT "app_productorder"."category" FROM "app_productorder"

มีสองสิ่งที่ต้องจำไว้ที่นี่ ขั้นแรกสิ่งนี้จะส่งกลับValuesQuerySetซึ่งทำงานแตกต่างจากไฟล์QuerySet. เมื่อคุณเข้าถึงพูดองค์ประกอบแรกของq(ด้านบน) คุณจะได้รับพจนานุกรม , ProductOrderไม่เป็นตัวอย่างของ

ที่สองก็จะเป็นความคิดที่ดีในการอ่านโน้ตเตือนdistinct()ในเอกสารเกี่ยวกับการใช้ ตัวอย่างข้างต้นใช้งานได้ แต่ชุดค่าผสมทั้งหมดdistinct()และvalues()อาจใช้ไม่ได้

PS : เป็นความคิดที่ดีที่จะใช้ชื่อตัวพิมพ์เล็กสำหรับฟิลด์ในแบบจำลอง ในกรณีของคุณนี่หมายถึงการเขียนแบบจำลองของคุณใหม่ดังที่แสดงด้านล่าง:

class ProductOrder(models.Model):
    product  = models.CharField(max_length=20, primary_key=True)
    category = models.CharField(max_length=30)
    rank = models.IntegerField()

1
วิธีการที่อธิบายไว้ด้านล่างมีให้ใช้งานแล้วใน django 1.4 และเป็นสิ่งที่ดีหากคุณต้องการอินสแตนซ์ ProductOrder ที่มีข้อมูลแตกต่างกัน ;-)
Jonathan Liuti

66

มันค่อนข้างง่ายจริงๆถ้าคุณใช้ PostgreSQLเพียงแค่ใช้distinct(columns)( เอกสารประกอบ )

Productorder.objects.all().distinct('category')

โปรดทราบว่าคุณลักษณะนี้รวมอยู่ใน Django ตั้งแต่ 1.4


@lazerscience, @Manoj Govindan: ฉันขอโทษคุณพูดถูก ดูเหมือนว่าฉันได้ติดตั้ง Django เพื่อเพิ่มคุณสมบัตินั้นแล้ว ฉันได้เพิ่มลิงค์ไปยังแพทช์
Wolph

3
ตอนนี้อยู่ใน Django SVN และจะอยู่ใน Django 1.4
Will Hardy

14
หมายเหตุ: เว้นแต่คุณจะใช้ PostgreSQL คุณไม่สามารถให้อาร์กิวเมนต์ () ที่แตกต่างกันได้ ติดดีที่สุดกับโซลูชันที่ยอมรับข้างต้น
Mark Chackerian

ในการทดสอบนี้can_distinct_on_fieldsดูเหมือนจะเป็น Postgres เท่านั้น
Skylar Saveland

4
บวก 1 แต่all()ไม่จำเป็นที่นี่
Antony Hatchkins

17

คำตอบอื่น ๆ ใช้ได้ดี แต่นี่เป็นเพียงเล็กน้อยที่สะอาดกว่าเนื่องจากจะให้ค่าเช่นเดียวกับที่คุณจะได้รับจากแบบสอบถาม DISTINCT โดยไม่มีส่วนใด ๆ จาก Django

>>> set(ProductOrder.objects.values_list('category', flat=True))
{u'category1', u'category2', u'category3', u'category4'}

หรือ

>>> list(set(ProductOrder.objects.values_list('category', flat=True)))
[u'category1', u'category2', u'category3', u'category4']

และใช้งานได้โดยไม่ต้องใช้ PostgreSQL

สิ่งนี้มีประสิทธิภาพน้อยกว่าการใช้. distinct () โดยสันนิษฐานว่า DISTINCT ในฐานข้อมูลของคุณเร็วกว่า python setแต่เหมาะสำหรับการดึงข้อมูลรอบ ๆ เชลล์


values_listไม่ใส่DISTINCTในแบบสอบถาม sql ดังนั้นสิ่งนี้จะนำมาซึ่งค่าหลายค่าหากมี
mehmet

13

ผู้ใช้เรียงลำดับตามฟิลด์นั้นแล้วทำการแยก

ProductOrder.objects.order_by('category').values_list('category', flat=True).distinct()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.