Cách chuyển đổi Django QuerySet thành một danh sách


121

Tôi có những thứ sau:

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

sau đó sau:

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)

Tôi gặp lỗi:

'QuerySet' object has no attribute 'remove'

Tôi đã thử mọi cách để chuyển QuerySet thành một tập hợp hoặc danh sách tiêu chuẩn. Không có gì hoạt động.

Làm cách nào để xóa một mục khỏi QuerySet để nó không xóa nó khỏi cơ sở dữ liệu và không trả lại một QuerySet mới (vì nó nằm trong một vòng lặp sẽ không hoạt động)?

Câu trả lời:


42

Bạn có thể làm điều này:

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)

Đọc khi QuerySets được đánh giá và lưu ý rằng không tốt khi tải toàn bộ kết quả vào bộ nhớ (ví dụ: thông qua list()).

Tài liệu tham khảo: itertools.ifilter

Cập nhật liên quan đến nhận xét:

Có nhiều cách khác nhau để làm điều này. Một (có lẽ không phải là tốt nhất về bộ nhớ và thời gian) là làm chính xác như vậy:

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)

tôi đã thêm một dòng nữa vào mẫu mã của mình ở trên, xóa cùng một mục nhập khỏi exising_question_answers. có thể sử dụng ifilter cho điều đó bằng cách nào đó không?
john

Tôi sẽ đánh dấu điều này là đúng vì tôi không biết về bộ lọc và đã quên về lambdas.
john

315

Tại sao không chỉ gọi list()trên Queryset?

answers_list = list(answers)

Điều này cũng sẽ đánh giá QuerySet/ chạy truy vấn. Sau đó, bạn có thể xóa / thêm khỏi danh sách đó.


9
Hãy cẩn thận với điều này. Khi bạn chuyển nó vào danh sách aa, lá cờ khác biệt có thể bị bỏ qua.
rh0dium

Tôi có thể làm điều đó một cách độc lập, nhưng tôi có thể làm điều đó trong queryset ở dạng django. Bất kỳ ý tưởng tại sao?
ismailsunni.

Nếu vậy, hãy truyền tới setrồi quay lại listđể nhận những cái duy nhất.
radtek

36

Có một chút khó khăn để làm theo những gì bạn đang thực sự cố gắng làm. Câu lệnh đầu tiên của bạn có vẻ như bạn có thể đang tìm nạp cùng một đối tượng QuerySet of Answer hai lần. Đầu tiên thông qua answer_set.answers.all()và sau đó một lần nữa qua .filter(id__in=...). Kiểm tra kỹ phần shell và xem điều này có cung cấp cho bạn danh sách các câu trả lời bạn đang tìm kiếm hay không:

answers = answer_set.answers.all()

Sau khi bạn đã làm sạch điều đó để bạn (và những người khác đang làm việc trên mã) dễ đọc hơn một chút, bạn có thể muốn xem xét .exclude ()tra cứu trường __in .

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

Việc tra cứu ở trên có thể không đồng bộ với định nghĩa mô hình của bạn nhưng nó có thể giúp bạn đủ gần để tự hoàn thành công việc.

Nếu bạn vẫn cần nhận danh sách các giá trị id thì bạn muốn chơi với .values_list () . Trong trường hợp của bạn, bạn có thể sẽ muốn thêm căn hộ tùy chọn = True.

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

Cảm ơn câu trả lời của bạn. Rất tiếc, tôi đã không cung cấp đủ chi tiết để cho thấy rằng tôi không thể sử dụng cách tiếp cận của bạn.
john

1
Giải pháp tốt nhất cho vấn đề được mô tả. Tôi muốn thêm new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istruble
aquaman

Cách sạch sẽ nhất là flat=TrueCảm ơn !!!!!!!
Cho

18

Bằng cách sử dụng toán tử lát cắt với tham số bước sẽ gây ra đánh giá bộ truy vấn và tạo danh sách.

list_of_answers = answers[::1]

hoặc ban đầu bạn có thể đã làm:

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

Theo như tôi biết, django queryset không hỗ trợ lập chỉ mục phủ định.
Alexey Sidash

Được rồi, Alexey. Bạn đang ở ngay đây. Tôi đã cập nhật câu trả lời.
Ankit Singh,

15

Bạn có thể chuyển đổi trực tiếp bằng cách sử dụng listtừ khóa. Ví dụ:

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

Sử dụng đoạn mã trên, bạn có thể chuyển đổi trực tiếp kết quả tập hợp truy vấn thành một list.

Đây listlà từ khóa và objlà kết quả của tập truy vấn và list1là biến trong biến đó, chúng tôi đang lưu trữ kết quả được chuyển đổi trong đó list.


1
Nhưng nếu bạn làm điều này, nó không hoạt động: list1 = list(emp.objects.all())điều này có vẻ phản trực quan.
geoidesic

4

Tại sao không chỉ gọi .values('reqColumn1','reqColumn2')hoặc .values_list('reqColumn1','reqColumn2')trên bộ truy vấn?

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

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

HOẶC LÀ

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

result = [(value1,value2)]

Bạn có thể thực hiện tất cả các thao tác trên QuerySet này mà bạn thực hiện cho danh sách.


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)

mã này chuyển đổi django queryset thành python list


0

Hãy thử điều này 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)

Nó sẽ trả về cho bạn một danh sách với các giá trị cột được chỉ định


0

thay vào đó, remove()bạn có thể sử dụng exclude()hàm để xóa một đối tượng khỏi bộ truy vấn. cú pháp của nó tương tự nhưfilter()

ví dụ : -

qs = qs.exclude(id= 1)

trong đoạn mã trên, nó xóa tất cả các đối tượng khỏi qs với id '1'

thông tin bổ sung : -

filter()được sử dụng để chọn các đối tượng cụ thể nhưng exclude()được sử dụng để loại bỏ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.