NoReverseMatch problem with my tutorial for Django - python

Going through the Django Tutorial in Python Crash Course and am facing a wall. The error I get is
'Reverse for 'topic' with arguments '('',)' not found. 1 pattern(s) tried: ['topics/(?P<topic_id>\\d+)/$']'.
This is my urls.py
from django.conf.urls import URL
from . import views
urlpatterns = [
# the actual url patter is a call to the url () function, which takes three arguments
# Home page
url(r'^$', views.index, name='index'),
#Show all topics
url(r'^topics/$', views.topics, name='topics'),
# Detail page for a single topic
url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
]
app_name= 'learning_logs'
views.py
from django.shortcuts import render
from .models import Topic
def index(request):
"""The home page for Learning Log"""
return render(request, 'learning_logs/index.html')
def topics(request):
"""Show all topics."""
topics = Topic.objects.order_by('date_added')
context = {'topics' : topics}
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
"""Show a single topic and all its entries."""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
topic.html
{%extends 'learning_logs/base.html' %}
{%block content%}
<p>Topic: {{topic}}</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{{entry.date_added|date:'M d, Y H:i'}}</p>
<p>{{entry.text| linebreaks}}</p>
</li>
{% empty %}
<li>
There are no entries for this topic yet.
</li>
{% endfor %}
</ul>
{%endblock content%}
I've read through some of the Django documentation but I'm not comprehending enough to solve this problem on my own. If I need to add some more code to help please let me know. All help is really appreciated.
Edit:
Topics.html
{%extends 'learning_logs/base.html'%}
{% block content%}
<p>Topics</p>
<ul>
{%for topic in topics%}
<li>
{{topic}}
</li>
{%empty%}
<li>No topics have been added yet</li>
{%endfor%}
</ul>
{% endblock content%}

The problem is in topics.html. Here's the loop that shows each topic:
{%for topic in topics%}
<li>
{{topic}}
</li>
{%empty%}
<li>No topics have been added yet</li>
{%endfor%}
The variable topic_id is not defined. That should be topic.id, which accesses the id attribute of topic.

In your template you are trying to access topic but in views.py you didn't pass topic variable to context. pass topic in your context variable:
def topic(request, topic_id):
"""Show a single topic and all its entries."""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries, 'topic': topic}
return render(request, 'learning_logs/topic.html', context)

Related

Dajngo template not rendering content

When I render blogpost.html page I can't see any content in my page.
My urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='Blog_home'),
path('<slug:slug>', views.blogpost, name='blogpost'),
]
my views.py
When I print blogpost function's query I got null value
from django.shortcuts import render
from django.http import HttpResponse
from blog.models import Post
# Create your views here.
def index(request):
post = Post.objects.all()
context = {'post':post}
return render(request, 'blog/bloghome.html', context)
def blogpost(request, post_id):
post = Post.objects.filter(slug=slug)
print(post)
context = {'post':post}
return render(request, 'blog/blogpost.html', context)
Template Name:- blogpost.html
{% extends 'basic.html' %}
{% block title %}Blog{% endblock title %}
{% block body %}
<div class="contaier">
<div class="row">
<div class="col-md-8 py-4">
<h2 class=" blog-post-title">{{post.title}}</h2>
</div>
</div>
</div>
{% endblock body %}
If I write like this my blogpost.html template it works.
{% extends 'basic.html' %}
{% block title %}Blog{% endblock title %}
{% block body %}
<div class="contaier">
<div class="row">
<div class="col-md-8 py-4">
<h2 class=" blog-post-title">Django</h2>
</div>
</div>
</div>
{% endblock body %}
You're passing a queryset as a context. Your post object contains a queryset of Post objects, so you can't retrieve post.title, you need either to pass only one Post object to your template, or loop through all of your objects and then display post.title for each of them.
You probably need the first option, so you need to change several things.
In your urls.py, you defined your blogpost view by blogpost(request, post_id) whereas in your urls.py you defined your url as
path('<slug:slug>', views.blogpost, name='blogpost')
If you want to get an id from your url, you should define it as
path('<int:post_id>', views.blogpost, name='blogpost')
And in your blogpost view, you do
post = Post.objects.filter(slug=slug)
but your slug isn't defined because your named it post_id.
Once again, if you want to retrieve only a post_id, you should use
post = Post.objects.get(pk=post_id)
The problem is that you are not retrieving a post with this:
post = Post.objects.filter(slug=slug)
It's a queryset, which returns zero, one, or possibly >1 objects (the latter if the slugfield isn't specified unique)
Try:
post = Post.objects.get(slug=slug)
or to better handle failure
post = get_object_or_404( Post, slug=slug)
Django template language fails quietly. If something in {{ }} fails, you get a null string substituted, not a runtime error.

Reverse for 'topic' with arguments '('',)' not found. 1 pattern(s) tried: ['topics/(?P<topic_id>[0-9]+)/\\Z']

I am getting this error:
Reverse for 'topic' with arguments '('',)' not found. 1 pattern(s) tried: ['topics/(?P<topic_id>[0-9]+)/\\Z']
which I believe is stemming from my urls.py:
from django.urls import path
from . import views
urlpatterns=[
#your paths go here
path('', views.index, name='index'), # home page
path('topics/', views.topics, name='topics'),
path('topics/<int:topic_id>/', views.topic, name='topic') # add id arguemnt since each entry is linked to topic by id
]
here is the topics.html which links to topic.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %} <!--passed through context i guess?-->
<li>
{{ topic }}
</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}
and here is the views.py code for topic:
def topic(request, topic_id):
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added') # minus sign indicates reverse order
context = {'topic':topic, 'entries':entries}
return render(request, 'learning_logs/topic.html', context)
In your html you need topic.id not topics.id, so:
{{ topic }}
Or maybe:
{{ topic }}

TypeError: topics() missing 1 required positional argument: 'topic_id'

I'm following along a Django tutorial book to make a basic blogging application where users can write journal entries about whatever topic they choose. I've written the url, pattern, view, and template for my topic page but I keep getting this same error. but I think something is wrong with the url pattern.
urls.py
# Defines url patterns for learning_logs app
from django.conf.urls import url
from . import views
urlpatterns = [
# Home Page
url(r'^$', views.index, name='index'),
# Topic Main Page
url(r'^topics/$', views.topics, name='topics'),
# Detail page for a single topic
url(r"^topics/(?P<topic_id>\d+)/$", views.topics, name='topic'),
]
views.py
from django.shortcuts import render
from .models import Topic
# Create your views here.
def index(request):
# This is the home page for our learning_logs app
return render(request, 'learning_logs/index.html')
# This is the view for 'topics' page 9.5.20
def topics(request, topic_id):
'''show a single topic and its entries '''
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topics.html', context)
And the error:
TypeError: topics() missing 1 required positional argument: 'topic_id'
Any advice? Thank you.
EDIT**
What I'm trying to do is to have a page that lists all of the topics in general. When the link for one topic in particular is clicked, it will lead to the page for that particular topic.
Here's the code for the topics.html (all topics displayed) and topic.html (when one particular topic is chosen)..
topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>
{{ topic }}
</li>
{% empty %}
<li>No topics have been added yet</li>
{% endfor %}
</ul>
{% endblock content %}
and topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, YH:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
</li>
{% empty %}
<li>No topics have been added yet</li>
{% endfor %}
</ul>
{% endblock content %}
The error clearly specifies that the function is not getting "topic_id", so there can be two cases
First, if you are using a template to redirect to that function(or view) you are not providing id, in that case, I might want to have a look at your template
Second, it's because of complex URL patterns so switch to something more simple likepath('topics/<int:topic_id>/', views.topics, name='topics'),
Lastly do not follow tutorial word to word because of things changes with update.
Your view is expecting a parameter passed to it ...
def topics(request, topic_id):
But your url does not have one:
url(r'^topics/$', views.topics, name='topics'),
You need to change the url to be something like:
path('topics/<int:topic_id>/', views.topics, name='topics'),
This means you would access that specific record at the url:
yourdomain.com/topics/1/
The 1 would be passed to the view, and used in topic = Topic.objects.get(id=topic_id)
The fact that you also have the url:
url(r'^topics/$', views.topics, name='topics'),
confuses matters - what is this view going to show with no topic set? From your code I suspect you want a list view here, which should ideally link to a different view, and maybe be named topics-list for clarity and ease of access in reverse lookups later. Your topics view specifically states in the docstring it is for viewing a single record, so don'ttry and use it for multiple ones as well. Much simpler to create a distinct view for that.
Edit: I see you've updated your path in urls.py in the question now. That should work for the single access, but note that your link topics/ is still directing to the same view - i.e. it's looking for a single record, but you're not telling it which.

TemplateSyntaxError during Template rendering

Python/Django beginner here - I get this error:
Reverse for 'topic' with arguments '('',)' and keyword arguments '{}'
not found. 1 pattern(s) tried: ['topics/(?P\d+)/$']
when trying to load my template.
This is my template:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>
{{ topic }}
</li>
{% empty %}
<li>No topics for now</li>
{% endfor %}
</ul>
{% endblock content %}
This is my views.py
from django.shortcuts import render
from .models import Topic
# Create your views here.
def index(request):
'''Home page for learning log'''
return render(request, 'learning_logs/index.html')
def topics(request):
'''Show all topics'''
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
'''Show a single topic and all its entries'''
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
I have been on this a while now, read some previous answers here, but they all had to do with auth/login not working. Also tried removing the '' after the url as some answers suggested but it didnt work. I am using Python Crash Course: A Hands-On, Project-Based Introduction to Programming for my tutorials.
Any help will be appreciated.
Finally, this is my urls.py code
from django.conf.urls import url
from . import views
urlpatterns = [
# Home page
url(r'^$', views.index, name='index'),
url(r'^topics/$', views.topics, name='topics'),
url(r'^topics/(?P<topic_id>\d+)/$', views.topics, name='topic'),
According to the error, there was an argument passed into the url tag, but it was empty:
Reverse for 'topic' with arguments '('',)'...
That's because of the topic_id variable, it is not defined. You should use topic.id instead:
{{ topic }}

Redirecting after saving form on Django

I am working on extending the webapp we're left off with after completing the official Django Tutorial.
One of the functionalities I am looking to add is the ability for users to add polls themselves.
I am struggling with getting the page to process the data and then redirect to the index page ('/polls').
When I submit a new poll as a logged in user, I am returned to my index page, which is supposed to show most recently published polls, or in the event of no polls, the message "No polls are available."
For some reason, I always see "No polls are available", but once I click to the index page via a link on the site, it displays all of my polls, including my most recently created one, data intact!
Any thoughts here? I think I have included the relevant info below but happy to supply more. Thanks in advance for any help/advice.
views.py
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 Poll.objects.order_by('-pub_date')[:15]
#login_required
def add_poll(request):
ChoiceFormSet = formset_factory(ChoiceForm, extra=3, min_num=2, validate_min=2)
if request.method == 'POST':
form = PollForm(request.POST)
formset = ChoiceFormSet(request.POST)
if all([form.is_valid(), formset.is_valid()]):
poll = form.save()
for inline_form in formset:
if inline_form.cleaned_data:
choice = inline_form.save(commit=False)
choice.question = poll
choice.save()
return render(request, 'polls/index.html', {})
else:
form = PollForm()
formset = ChoiceFormSet()
return render(request, 'polls/add_poll.html', {'form': form, 'formset': formset})
add_poll.html
{% extends 'polls/base.html' %}
{% block title %}Add Poll{% endblock %}
{% block body_block %}
<form role="form" id="poll_form" method="post" action="{% url 'polls:add_poll' %}">
<h2 class="form-signin-heading">Add a Poll</h2>
{% csrf_token %}
<table>
{{ form }}
{{ formset }}
</table>
<br/>
<button class="btn btn-primary" type="submit" name="submit">Create Poll</button>
</form>
{% endblock %}
index.html
{% extends 'polls/base.html' %}
{% block body_block %}
{% if latest_question_list %}
<ul>
{% for poll in latest_question_list %}
<li>{{ poll.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
{% endblock %}
urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>\d+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^add_poll/$', views.add_poll, name='add_poll'),
url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
url(r'^profile_page/$', views.ProfileView.as_view(), name='profile_page'),
url(r'^edit_profile/$', views.edit_profile, name='edit_profile'),
)
When you save your form you are not redirecting.
Your are returning 'polls/index.html' with empty polls data, that's why you always get "No polls are available". But this is very incorrect, you must follow the Post/Redirect/Get (PRG) pattern, so instead of:
return render(request, 'polls/index.html', {})
do this:
return HttpResponseRedirect(reverse('polls:index'))
You don't do any redirect right now, you are just rendering your index template with an empty context (that's why you don't see anything). To redirect, you need to use HttpResponseRedirect when your form is valid.
So, please change line:
return render(request, 'polls/index.html', {})
(just over the else) to
return HttpResponseRedirect(reverse('index'))
I finally figured it out. I had to change my html form to this:
<form method="POST" action="{% url 'new_beam:beam_diagram' beam_id=1 %}" enctype="multipart/form-data">

Categories

Resources