so I started on the generic views section of the tutorial, until which point everything was smooth sailing, working perfectly and then I get this error:
Reverse for 'vote' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'polls/(?P[0-9]+)/vote/$']
Here is my urls.py:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name ='vote'),
]
And here is my views.py:
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.template import RequestContext, loader
from django.http import Http404
from .models import Choice, Quesion
from django.core.urlresolvers import reverse
from django.views import generic
# Create your views here.
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Quesion.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Quesion
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Quesion
template_name = 'polls/results.html'
def vote(request, question_id):
p = get_object_or_404(Quesion, pk=question_id)
try:
selected_choice = p.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
return render(request, 'polls/detail.html', {
'question': p,
'error_message':"No choice selected",
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results',args=(p.id,)))
And here is my detail.html
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_txt }} </label><br />
{% endfor %}
<input type="submit" value="vote" />
</form>
You have two problems. The first is that DetailView doesn't provide a question variable in the template, but provides one called object instead. So all instances of question in the template needs to be changed to object.
Secondly, the URL is expecting a keyword argument question_id, but you're passing a non-keyword argument to the {% url %} tag. You need to change that to say question_id=object.id. Your detail.html should look like this:
<h1>{{ object.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question_id=object.id %}" method="post">
{% csrf_token %}
{% for choice in object.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_txt }} </label><br />
{% endfor %}
<input type="submit" value="vote" />
</form>
Related
I decided to learn Django and started with the 'Django Polls App' which I figured would be the most simple, I am gripping the idea of how it works but I am stuck. To learn a bit better, I changed the variables and names from the original docs to my own.
Example : question_text = q_text, Choice = Choices, choice_text = choice.. etc.
Now I can't figure out what's wrong with my code as I can't make the polls work. There is no error code but it simply doesn't display the number of votes or show a success sign. I was also following Traversy Media's Django Crash Course (Polls App).
My code :
views.py
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.template import loader
from .models import Question, Choices
def index(request):
latest_ques = Question.objects.order_by('-published')[:5]
context = {'latest_ques': latest_ques}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choices_set.get(pk=request.POST['choices'])
except (KeyError, Choices.DoesNotExist):
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
models.py
from django.db import models
class Question(models.Model):
q_text = models.CharField(max_length=200)
published = models.DateTimeField('date published')
def __str__(self):
return self.q_text
class Choices(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice
details.html
{% extends 'base.html' %}
{% block content %}
<a class="btn btn-secondary btn-sm mb-3" href="{% url 'polls:index' %}">Back To Polls</a>
<h1 class="text-center mb-3">{{ question.q_text }}</h1>
{% if error_message %}
<p class="alert alert-danger">
<strong>{{ error_message }}</strong>
</p>
{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choices in question.choices_set.all %}
<div class="form-check">
<input type="radio"
name="choices"
class="form-check-input"
id="choices{{ forloop.counter }}"
value="{{ choices.id }}">
<label for="choices{{ forloop.counter }}">{{ choices.choice }}</label>
</div>
{% endfor %}
<input type="submit" value="Vote" class="btn btn-success btn-lg btn-block mt-4" />
</form>
{% endblock %}
results.html
{% extends 'base.html' %}
{% block content %}
<h1 class="mb-5 text-center">{{ question.q_text }}</h1>
<ul class="list-group mb-5">
{% for choices in question.choices_set.all %}
<li class="list-group-item">
{{ choices.choice }} <span class="badge badge-success float-right">{{ choices.votes }} vote{{ choices.votes | pluralize }}</span>
</li>
{% endfor %}
</ul>
<a class="btn btn-secondary" href="{% url 'polls:index' %}">Back To Polls</a>
<a class="btn btn-dark" href="{% url 'polls:detail' question.id %}">Vote Again?</a>
{% endblock %}
urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
I've been on the internet for hours and can't figure it out. Not getting a proper answer. Thought I'd try my luck here.
I've tried to change the names of multiple variables, I've had many errors throughout but this one I can't figure out. The solution would actually be quite simple I know it but can't really put a finger on it. Thanks.
Nevermind, I found out that there were some misspelled variables. It worked after I went line by line to find the error.
I keep getting this when trying to load da page:
NoReverseMatch at /polls/
Reverse for 'vote' with arguments '('',)' not found. 1 pattern(s) tried: ['polls/(?P<question_id>[0-9]+)/vote/$']
In template C:\Users\sarah\Desktop\django2\myproject\my_site\polls\templates\polls\index.html, error at line 20
line 20:
<form action="{% url 'polls:vote' question.id %}" method="post">
I am a complete beginner at django, css, html, ... I kept checking in with the tutorial, comparing my code with the code reference in the tutorial, however I see no mistake.
My index.html:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
The vote function in views.py:
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
urls.py:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
Thank you.
The main reason here is you are using your index.html with the form where you should really have this in polls/detail where you have access to a question object by pk. Right now you are trying to access the id property of question but question is undefined in your index.html.
Place the following in your polls/details.html
<h1>{{ question.question_text }}</h1>
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
Then, navigate to polls/1 or whatever question.id you want and then try and use the form.
This is the polls app tutorial from the Django Docs.
When I go to the first question http://127.0.0.1:8000/polls/1/, select an option and click 'Vote', I get the error message.
error message
views.py:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
# request.POST['choice'] returns ID of the selected choice as a string
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return a HttpResponseRedirect after successfully dealing with POST data.
# This prevents the data from being posted twice if a user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=question_id, ))
polls/urls.py:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
polls/templates/polls/index.html:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
polls/templates/polls/detail.html:
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"/>
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote"/>
</form>
polls/templates/polls/results.html:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
Vote again?
Can anyone please help?
The problem is that you write:
return HttpResponseRedirect(reverse('polls:results', args=question_id, ))
Now args is used for positional arguments, and there can be (in theory) multiple. So it should be a collection of items. For example:
return HttpResponseRedirect(reverse('polls:results', args=[question_id], ))
Note: in the tutorial they write args=(question_id,). Now that is something different than args=question_id. In Python a (0, ) is not an integer, but a 1-tuple containing one element: 0. In short: the brackets matter.
But there is no need to do all this wrapping. Django has a shorcut redirect(..) [Django-doc], to build HttpResponseRedirects in a more convenient way:
return redirect('polls:results', question_id)
This takes *args and **kwargs itself as positional and named arguments. So you can write it as if you were calling the view directly as function (with the name of the view in front).
I'm following the Django tutorial process, currently located on part 6.
I get an error when I click on the list from my web page. I looked up where the problem occurred, but I could not find it.
This is the message from a web browser:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/polls/1//
Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order:
polls/ [name='index']
polls/ <int:pk>/ [name='detail']
polls/ <int:pk>/results/ [name='results']
polls/ <int:question_id>/vote/ [name='vote']
admin/
The current path, polls/1//, didn't match any of these.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
traceback
"GET /polls/1// HTTP/1.1" 404 2703
mysite/polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from django.utils import timezone
from .models import Choice, Question
# ...
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""
Return the last five published questions (not including those set to be
published in the future).
"""
return Question.objects.filter(
pub_date__lte=timezone.now()
).order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
def get_queryset(self):
"""
Excludes any questions that aren't published yet.
"""
return Question.objects.filter(pub_date__lte=timezone.now())
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
mysite/polls/urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
mysite/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
mysite/polls/templates/polls/index.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
mysite/polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
mysite/polls/templates/polls/result.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
Vote again?
You have two slashes ('//') at the end of your url, this should be just one:
http://localhost:8000/polls/1/
More specifically, in your polls/index.html template, you have the following line:
<li>{{ question.question_text }}</li>
Of that line, this part generates the url for you:
{% url 'polls:detail' question.id %}
that becomes:
http://localhost:8000/polls/1/
But you have added an extra slash behind it, look at the end of the below string:
"{% url 'polls:detail' question.id %}/"
Remove that, and I think your code should work.
I am getting the following error while running the django server :
Reverse for 'results' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'library/(?P<student_id>[0-9]+)/results/$']
Note : The error goes off if I remove this line from index.html file.
<form action="{% url 'library:results' student.id %}" method="post">
But without this, I cannot do the post request .
This is my result.html template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
hey {{ student.name }}
</body>
</html>
my views.py file
from django.http import Http404
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from .models import Student, Choice
from django.urls import reverse
def vote(request, student_id):
student = get_object_or_404(Student, pk=student_id)
try:
selected_choice = Student.Choice_set.get(pk=request.POST['Choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'library/results.html', {
'student': student,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('library:results', args=(student.id,)))
def index(request):
students_list = Student.objects.all()
template = loader.get_template('library/index.html')
context = {
'students_list': students_list,
}
return HttpResponse(template.render(context, request))
def detail(request, student_id):
try:
student = Student.objects.get(pk=student_id)
except Student.DoesNotExist:
raise Http404("Student does not exist")
return render(request, 'library/detail.html', {'student': student})
def results(request, student_id):
student = get_object_or_404(Student, pk=student_id)
return render(request, 'library/results.html', {'student': student})
the index.htmp template is this
<h1>{{ student.name }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'library:results' student.id %}" method="post">
{% csrf_token %}
{% for student in students_list %}
<input type="checkbox" name="student" id="student{{ forloop.counter }}" value="{{ student.id }}"/>
<label for="student{{ forloop.counter }}">{{ student.name }}</label><br/>
{% endfor %}
<input type="submit" value="Vote" />
</form>
I have tried various things , but none is working. I can't remove the form action from the code since that would make it useless.
student doesn't exist at that point, so there is no value for student.id.
You should move your for tag so it is before the form element - and the matching endfor needs to come after the form close.
The problem is index.html file.
You are passing student.id into form action but there student is not a defined variable,you should move the action and form tag inside the for loop.The resulting code would be like this :
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% for student in students_list %}
<h1>{{ student.name }}</h1>
<form action="{% url 'library:results' student.id %}" method="post"> {% csrf_token %}
<input type="checkbox" name="student" id="student{{ forloop.counter }}" value="{{ student.id }}"/>
<label for="student{{ forloop.counter }}">{{ student.name }}</label><br/>
<input type="submit" value="Vote" />
</form>
{% endfor %}