วิธีการแปลง Django QuerySet เป็นรายการ


121

ฉันมีสิ่งต่อไปนี้:

answers = Answer.objects.filter(id__in=[answer.id for answer in answer_set.answers.all()])

หลังจากนั้น:

for i in range(len(answers)):
    # iterate through all existing QuestionAnswer objects
    for existing_question_answer in existing_question_answers:
        # if an answer is already associated, remove it from the
        # list of answers to save
        if answers[i].id == existing_question_answer.answer.id:
            answers.remove(answers[i])           # doesn't work
            existing_question_answers.remove(existing_question_answer)

ฉันได้รับข้อผิดพลาด:

'QuerySet' object has no attribute 'remove'

ฉันได้ลองทุกประเภทเพื่อแปลง QuerySet เป็นชุดหรือรายการมาตรฐาน ไม่มีอะไรทำงาน

ฉันจะลบรายการออกจาก QuerySet ได้อย่างไรจึงจะไม่ลบออกจากฐานข้อมูลและไม่ส่งคืน QuerySet ใหม่ (เนื่องจากอยู่ในลูปที่ใช้ไม่ได้)

คำตอบ:


42

คุณสามารถทำได้:

import itertools

ids = set(existing_answer.answer.id for existing_answer in existing_question_answers)
answers = itertools.ifilter(lambda x: x.id not in ids, answers)

อ่านเมื่อมีการประเมิน QuerySetsและโปรดทราบว่าการโหลดผลลัพธ์ทั้งหมดลงในหน่วยความจำนั้นไม่ดี (เช่นผ่านlist())

อ้างอิง: itertools.ifilter

อัปเดตเกี่ยวกับความคิดเห็น:

มีหลายวิธีในการดำเนินการนี้ หนึ่ง (ซึ่งอาจไม่ใช่สิ่งที่ดีที่สุดในแง่ของหน่วยความจำและเวลา) คือการทำสิ่งเดียวกัน:

answer_ids = set(answer.id for answer in answers)
existing_question_answers = filter(lambda x: x.answer.id not in answers_id, existing_question_answers)

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

ฉันจะทำเครื่องหมายว่าถูกต้องเพราะฉันไม่รู้เกี่ยวกับตัวกรองและลืมเรื่องแลมบ์ดาไปแล้ว
ห์น

315

ทำไมไม่เพียงโทรlist()บนQueryset?

answers_list = list(answers)

นอกจากนี้ยังจะประเมินQuerySet/ เรียกใช้แบบสอบถาม จากนั้นคุณสามารถลบ / เพิ่มจากรายการนั้นได้


9
ระวังเรื่องนี้ด้วย เมื่อคุณส่งสิ่งนี้ไปยังรายการธงที่แตกต่างกันอาจถูกเพิกเฉย
rh0dium

ฉันสามารถทำได้โดยอิสระ แต่ฉันสามารถทำได้ในแบบสอบถามในรูปแบบ django คิดว่าทำไม?
ismailsunni

ถ้าเป็นเช่นนั้นให้ส่งไปsetแล้วกลับไปlistเพื่อรับรายการที่ไม่ซ้ำกัน
radtek

36

เป็นเรื่องยากเล็กน้อยที่จะทำตามสิ่งที่คุณพยายามทำจริงๆ คำสั่งแรกของคุณดูเหมือนว่าคุณอาจเรียกวัตถุ QuerySet of Answer ที่เหมือนกันสองครั้ง ครั้งแรกผ่านanswer_set.answers.all()ทาง.filter(id__in=...). ตรวจสอบอีกครั้งในเชลล์และดูว่าจะให้รายการคำตอบที่คุณต้องการหรือไม่:

answers = answer_set.answers.all()

เมื่อคุณมีที่ทำความสะอาดขึ้นดังนั้นจึงเป็นเรื่องง่ายที่เล็ก ๆ น้อย ๆ สำหรับคุณ (และอื่น ๆ ที่ทำงานเกี่ยวกับรหัส) ในการอ่านคุณอาจต้องการที่จะมองเข้าไป.exclude ()และ__in ค้นหาข้อมูล

existing_question_answers = QuestionAnswer.objects.filter(...)

new_answers = answers.exclude(question_answer__in=existing_question_answers)

การค้นหาข้างต้นอาจไม่ซิงค์กับคำจำกัดความของแบบจำลองของคุณ แต่อาจทำให้คุณเข้าใกล้พอที่จะทำงานให้เสร็จได้

หากคุณยังต้องการที่จะได้รับรายการของค่า ID แล้วคุณต้องการที่จะเล่นกับ.values_list () ในกรณีของคุณคุณอาจต้องการเพิ่ม flat = True

answers.values_list('id', flat=True)

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

1
ทางออกที่ดีที่สุดสำหรับปัญหาที่อธิบายไว้ ฉันต้องการเพิ่มnew_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istruble
aquaman

วิธีที่สะอาดที่สุดคือflat=Trueขอบคุณ !!!!!!!
โช

18

โดยการใช้ตัวดำเนินการ slice พร้อมพารามิเตอร์ขั้นตอนซึ่งจะทำให้เกิดการประเมินชุดข้อมูลและสร้างรายการ

list_of_answers = answers[::1]

หรือในตอนแรกคุณสามารถทำได้:

answers = Answer.objects.filter(id__in=[answer.id for answer in
        answer_set.answers.all()])[::1]

เท่าที่ฉันทราบ django queryset ไม่สนับสนุนการสร้างดัชนีเชิงลบ
Alexey Sidash

โอเค Alexey คุณอยู่ที่นี่ ฉันได้อัปเดตคำตอบแล้ว
Ankit Singh

16

คุณสามารถแปลงโดยตรงโดยใช้listคำหลัก ตัวอย่างเช่น:

obj=emp.objects.all()
list1=list(obj)

การใช้รหัสด้านบนคุณสามารถแปลงผลลัพธ์ชุดแบบสอบถามเป็นไฟล์list.

นี่listเป็นหลักและobjเป็นผลมาจากชุดแบบสอบถามและการเป็นตัวแปรในตัวแปรที่เราจะจัดเก็บผลการแปลงซึ่งlist1list


1
แต่ถ้าคุณทำเช่นนี้จะไม่ได้ผลlist1 = list(emp.objects.all())ซึ่งดูเหมือนจะใช้งานง่าย
geoidesic

4

ทำไมไม่โทร .values('reqColumn1','reqColumn2')หรือ.values_list('reqColumn1','reqColumn2')สอบถาม?

answers_list = models.objects.values('reqColumn1','reqColumn2')

result = [{'reqColumn1':value1,'reqColumn2':value2}]

หรือ

answers_list = models.objects.values_list('reqColumn1','reqColumn2')

result = [(value1,value2)]

คุณสามารถดำเนินการทั้งหมดใน QuerySet นี้ซึ่งคุณทำเพื่อรายการ


1
def querySet_to_list(qs):
    """
    this will return python list<dict>
    """
    return [dict(q) for q in qs]

def get_answer_by_something(request):
    ss = Answer.objects.filter(something).values()
    querySet_to_list(ss) # python list return.(json-able)

รหัสนี้แปลง django queryset เป็น python list


0

values_list('column_name', flat=True)ลองนี้

answers = Answer.objects.filter(id__in=[answer.id for answer in answer_set.answers.all()]).values_list('column_name', flat=True)

มันจะส่งคืนรายการที่มีค่าคอลัมน์ที่ระบุ


0

แทน remove()ที่คุณสามารถใช้exclude()ฟังก์ชั่นในการลบวัตถุจาก queryset มันคล้ายกับไวยากรณ์filter()

เช่น : -

qs = qs.exclude(id= 1)

ในโค้ดด้านบนจะลบวัตถุทั้งหมดออกจาก qs ด้วย id '1'

ข้อมูลเพิ่มเติม : -

filter()ใช้เพื่อเลือกวัตถุเฉพาะ แต่exclude()ใช้เพื่อลบ

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