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 }}
Related
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 }}
Currently working through the Python Crash Course Django section I've got everything but the edit posts page working. I added the edit post link under each post but this error now displays when you try to view the homepage:
Reverse for 'edit_post' with no arguments not found. 1 pattern(s) tried: ['edit_post/(?P<post_id>[0-9]+)/$']
Here is the code I've been using.
from django.db import models
# Create your models here.
class BlogPost(models.Model):
"""A topic the user is learning about"""
title = models.CharField(max_length=200)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""A place for the user to create a blog post"""
return self.title
Views
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogForm
# Create your views here.
def index(request):
"""The home page for Blog"""
return render(request, 'blogs/index.html')
def blogposts(request):
"""Show all blogposts"""
blogposts = BlogPost.objects.order_by('date_added')
context = {'blogposts': blogposts}
return render(request, 'blogs/blogposts.html', context)
def new_post(request):
"""Add a new post"""
if request.method != 'POST':
# No data submitted, create a blank form
form = BlogForm()
else:
# POST data submitted; process data
form = BlogForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:blogposts')
# Display a blank or invalid form
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
current_entry = BlogPost.objects.get(id=post_id)
if request.method != 'POST':
# Initial request; pre-fill form with current entry
form = BlogForm(instance=current_entry)
else:
form = BlogForm(instance=current_entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:index')
context = {'post':post, 'form':form}
return render(request, 'blogs/edit_post.html', context)
URLs
"""Defines URL patterns for blogs"""
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# Page that shows all topics
path('blogposts/', views.blogposts, name='blogposts'),
# Page that displays a single post
path('new_post/', views.new_post, name='new_post'),
# Page for editing a post
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
blogposts.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Blog Posts</p>
<ul>
{% for blogpost in blogposts %}
<h1>{{ blogpost }}</h1>
<p>{{ blogpost.body }}</p>
Edit post
{% empty %}
<li>No blogs have been posted yet</li>
{% endfor %}
</ul>
Create a new post
{% endblock content %}
edit_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Edit post:</p>
<form action="{% url 'blogs:edit_post' post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save Changes</button>
</form>
{$ endblock content %}
You need to pass the id of the blog post you want to edit.
So in your blogposts.html try:
"{% url 'blogs:edit_post' blogpost.pk %}"
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)
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.
I am currently working on a tutorial in the "Python Crash course" Book.
The tutorial is about creating a "Learning Log" Webapp with Django.
The idea of the app is to allow users to:
1. create "Topics" they have learned about
2. add "Entries" to those Topics, describing details they have learned specific to those topics
I am currently stuck at creating an Entry form and receive an Error, when I run http://127.0.0.1:8000/new_entry/1
NoReverseMatch at /new_entry/1
Reverse for 'topic' with arguments '('',)' not found. 1 pattern(s) tried: ['topics/(?P<topic_id>[0-9]+)/$']
Request Method: GET
Request URL: http://127.0.0.1:8000/new_entry/1
Django Version: 3.0.5
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'topic' with arguments '('',)' not found. 1 pattern(s) tried: ['topics/(?P<topic_id>[0-9]+)/$']
Exception Location: C:\Users\DR\Desktop\learning_log\ll_env\lib\site-packages\django\urls\resolvers.py in _reverse_with_prefix, line 677
Python Executable: C:\Users\DR\Desktop\learning_log\ll_env\Scripts\python.exe
Python Version: 3.8.2
Python Path:
['C:\\Users\\DR\\Desktop\\learning_log',
'C:\\Program '
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_3.8.752.0_x64__qbz5n2kfra8p0\\python38.zip',
'C:\\Program '
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_3.8.752.0_x64__qbz5n2kfra8p0\\DLLs',
'C:\\Program '
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_3.8.752.0_x64__qbz5n2kfra8p0\\lib',
'C:\\Users\\DR\\AppData\\Local\\Microsoft\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0',
'C:\\Users\\DR\\Desktop\\learning_log\\ll_env',
'C:\\Users\\DR\\Desktop\\learning_log\\ll_env\\lib\\site-packages']
Server time: Wed, 15 Apr 2020 19:46:06 +0000
The forms.py file:
from django import forms
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
The urls.py file:
from django.urls import path
from . import views
app_name = "learning_logs"
urlpatterns = [
# --snip--
# Page for adding new entry
path('new_entry/<int:topic_id>', views.new_entry, name='new_entry'),
]
And views.py:
from django.shortcuts import render, redirect
from .models import Topic
from .forms import TopicForm, EntryForm
#--snip
def new_entry(request, topic_id):
"""Add a new entry for a particular topic."""
topic = Topic.objects.get(id=topic_id)
if request.method != 'POST':
# No data submitted; create a blank form.
form = EntryForm()
else:
# POST data submitted; process data.
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return redirect('learning_logs:topic', topic_id=topic_id)
# Display a blank or invalid form.
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
And finally the new_entry.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>{{ topic }}</p>
<p>Add a new entry:</p>
<form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Add entry</button>
</form>
{% endblock content %}
And topic.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<p>
Add new entry
</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 %}
Any help would be much appreciated!
The mistake was in new_entry.html:
It should read:
{% url 'learning_logs:topic' topic.id %}
and not:
{% url 'learning_logs:topic' topic_id %}
Thanks to Klaus for pointing me at the line!