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लिए फिर से कास्ट करें और वापस जाएं ।
रेडटेक

36

यह पालन करना थोड़ा कठिन है कि आप वास्तव में क्या करने की कोशिश कर रहे हैं। आपका पहला कथन ऐसा लगता है कि आप उत्तर वस्तुओं के समान सटीक क्वेरी को दो बार प्राप्त कर सकते हैं। पहले के माध्यम से 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)

उपरोक्त लुकअप आपकी मॉडल परिभाषाओं के साथ तालमेल नहीं बिठा सकता है, लेकिन यह संभवत: आपको काम पूरा करने के लिए पर्याप्त रूप से बंद कर देगा।

यदि आपको अभी भी आईडी मानों की सूची प्राप्त करने की आवश्यकता है तो आप .values_list () के साथ खेलना चाहते हैं । आपके मामले में आप संभवतः वैकल्पिक फ्लैट जोड़ना चाहेंगे = ट्रू।

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

आपके उत्तर के लिए धन्यवाद। दुर्भाग्य से मैंने यह दिखाने के लिए पर्याप्त विवरण नहीं दिया कि मैं आपके दृष्टिकोण का उपयोग नहीं कर सकता।
जॉन

1
वर्णित समस्या के लिए सबसे अच्छा समाधान। मैं new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))
एक्वामन

सबसे साफ तरीका है flat=Trueधन्यवाद !!!!!!
चो

18

स्टेप पैरामीटर के साथ स्लाइस ऑपरेटर के उपयोग से जो क्वेरीसेट के मूल्यांकन का कारण बनता है और एक सूची बनाता है।

list_of_answers = answers[::1]

या शुरू में आप कर सकते थे:

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

जहाँ तक मुझे पता है, django query नेगेटिव इंडेक्सिंग का समर्थन नहीं करता है।
बजे एलेक्सी सिदश

ठीक है एलेक्सी। आप यहीं हैं। मैंने जवाब अपडेट कर दिया है।
अंकित सिंह

15

आप सीधे listकीवर्ड का उपयोग करके कन्वर्ट कर सकते हैं । उदाहरण के लिए:

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

उपरोक्त कोड का उपयोग करके आप सीधे क्वेरी सेट परिणाम को एक में बदल सकते हैं list

यहां listकीवर्ड है और objक्वेरी सेट का परिणाम है और list1उस वेरिएबल में वेरिएबल है जिसे हम कनवर्ट किए गए परिणाम को स्टोर कर रहे हैं list


1
लेकिन अगर आप ऐसा करते हैं तो यह काम नहीं करता है: list1 = list(emp.objects.all())जो प्रति-सहज लगता है।
भूगर्भिक

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 क्वेरी को परिवर्तित करता है


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()क्वेरीसेट से किसी ऑब्जेक्ट को हटाने के लिए फ़ंक्शन का उपयोग कर सकते हैं । यह वाक्य रचना के समान हैfilter()

जैसे : -

qs = qs.exclude(id= 1)

उपरोक्त कोड में यह id '1' के साथ qs से सभी ऑब्जेक्ट को हटा देता है

अतिरिक्त जानकारी : -

filter()विशिष्ट वस्तुओं का चयन exclude()करने के लिए उपयोग किया जाता है लेकिन निकालने के लिए उपयोग किया जाता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.