0

In my views.py, I do:

context_data = {}
all_answers = Answer.objects.all()

for i in range(0, len(all_answers)) :
    all_answers[i].text = modify_text(all_answers[i].text, request)

context_data ["all_answers"] = all_answers 
print(context_data ["all_answers"][0].text) #Check that it was modified

return render(request, 'template.html', context_data)

And in my templates I have like :

{% for answer in all_answers.all %}
   {{ answer.text}}
{% endfor %}

The check shows that the modification is made, yet it's my template the answer.text is the unmodified data from the database.

I saw that the type of the context_data ["all_answers"] is a queryset, that I guess is triggered during the template rendering, making any unsaved changes useless, how to make my changes show in the template?

I have tried :

context_data ["all_answers"] = list(all_answers) 

To load the queryset. The check works but then nothing shows in the template (1)

An error arises during the template render when I used this function to load the queryset into a list of dict.

I also saw a [linked question without answer].3

I don't want to save the changes as they are customized for each request (for each user basically).

** TLDR: How to see my modifications in the templates without saving the changes into the database ?**

PS: Using Python 3.6.8, Django 2.2.3.

shyamzzp
  • 115
  • 7
Eli O.
  • 1,543
  • 3
  • 18
  • 27

2 Answers2

2

Querysets are not data holders they are just lazy references, and get evaluated on runtime. The problem with your code is that you are modifying instances in queryset (which is also wrong way you should iterate using in operator like).

for answer in all_answers:
    answer.text = modify_text(answer.text, request)

The real problem is that you are calling all method on queryset in your template again all_answers.all which returns a fresh queryset and without changes you made so you should, in template, do

{% for answer in all_answers %}
   {{ answer.text}}
{% endfor %}
Nafees Anwar
  • 6,324
  • 2
  • 23
  • 42
1

In Python you should never iterate through range(len(something)), but always over the thing itself. In the case of Django querysets this is even more important, since accessing an item in an unevaluated queryset via its index ([i]) actually causes a separate request to the database each time.

Do this instead:

for answer in all_answers:
    answer.text = modify_text(answer.text, request)

context_data ["all_answers"] = all_answers 
print(context_data ["all_answers"][0].text) #Check that it was modified

Note that the loop evaluates the queryset, so the [0] there doesn't cause another db request.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I thought a "for - in" loop in Python didn't modify the content of the object ? Like : a = [1,2,3] for i in a : i = i + 1 print(a) #[1, 2, 3] .Thanks for the precision on the db requests, it sure is something to keep in mind ! – Eli O. Aug 12 '19 at 15:40
  • 1
    Sure, but you are not doing that; `answer` is a reference to the item, and you modify one of its attributes. – Daniel Roseman Aug 12 '19 at 15:42