Reputation: 309
I am running into a problem with a Django project I am currently working on.
I have a view in which I create a model instance via a POST request:
class CreatePollView(View):
template = "polls/create_poll.html"
@method_decorator(login_required)
def post(self, request):
question_text = request.POST['question']
pub_date = now()
new_question = Question(question_text=question_text, pub_date=pub_date)
new_question.save()
options_list = request.POST.getlist('options')
for option in options_list:
option_text = option
new_option = Option(option_text=option_text, question=new_question)
new_option.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
This works fine. I can add the question and its options to the DB and see that it has been added in the admin. But when I then call my index.html, in which I list all the question objects, it doesn't update.
class IndexView(View):
template = loader.get_template('polls/index.html')
questions = Question.objects.all()
context = {
'question_list': questions,
}
def get(self, request):
return HttpResponse(self.template.render(self.context, request))
And the template:
{% extends 'homepage/base.html' %}
{% block content %}
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>All Polls:</h1>
<div>
{% for question in question_list %}
<p><a href="{{ question.pk }}">{{ question }}</a></p>
{% endfor %}
<a href="new_poll" class="btn btn-primary">New Poll</a>
</div>
</div>
</div>
{% endblock %}
When I build an error into the view, then fix it and run the code again it updates the list. Question.objects.all()
But other than that the model changes are not displayed here when I post a new model instance. Can someone tell me what I am doing wrong?
EDIT: This only seems to happen with class based views. When I was using method views it worked fine.
def index(request):
question_list = Question.objects.all()
template = loader.get_template('polls/index.html')
context = {
'question_list': question_list,
}
return HttpResponse(template.render(context, request))
def new_poll(request):
if request.method == 'POST':
question_text = request.POST['question']
pub_date = now()
new_question = Question(question_text=question_text, pub_date=pub_date)
new_question.save()
options_list = request.POST.getlist('options')
# import pdb
# pdb.set_trace()
for option in options_list:
option_text = option
new_option = Option(option_text=option_text, question=new_question)
new_option.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
template = loader.get_template('polls/create_poll.html')
context = {
'user': request.user
}
return HttpResponse(template.render(context, request))
Upvotes: 2
Views: 5581
Reputation: 77942
Django is designed to work as a long running process (load once, serve forever), not as a CGI script where everything is reload on each and every HTTP request. This means that anything happening outside a function (ie at a module's top-level, in a class statement's body etc) is executed only once (per process) at module's first import (well, just as for any Python process actually - the point here is that it's a long running process, not a one-shot script).
So here:
class IndexView(View):
template = loader.get_template('polls/index.html')
questions = Question.objects.all()
context = {
'question_list': questions,
}
Those three statements in your class body are eval'd with the class
statement on your module's first import. From then those values won't be re-evaled for the process lifetime, so you indeed keep the same results for context['question_list']
from request to request, until you kill your server process and start a new one (which will get stale after the first request, etc).
You don't have the problem with the function-based view because your code executed on each request, yielding an up to date queryset.
To make a long story short, start by moving this code into your class get
method:
class IndexView(View):
def get(self, request):
template = loader.get_template('polls/index.html')
questions = Question.objects.all()
context = {
'question_list': questions,
}
return HttpResponse(template.render(context, request))
Then you may want to take a bit more time learning about django's forms, modelforms, shortcuts etc, and if you insist on using class-based views then learn to use the various mixins too.
Upvotes: 7