Django Dynamic Links NoReverseMatch - python

I'm trying to dynamically create pages based on the movie title of the link clicked. I keep getting an error though when I try to set the link though "u'app_name' is not a registered namespace"
my index.html looks like this and it works when the link isn't set:
{% for movie in movies %}
<li data-id="{{ movie.id }}"><span class="title">{{ movie.title }}</span> ({{ movie.year }}) - {{ movie.genre}}<a class="delete">X</a></li>
{% endfor %}
my views.py for the dynamic url pages look like this:
def detail(request, movie_title):
return render(request, 'detail.html', {'movie_object':movie_object})
my urls.py for this specific section looks like this:
url(r'(?P<movie_title>[_\w+])$', views.detail, name='detail')

The problem was in
return render(request, 'detail.html', {'movie_object':movie_object})
movie_object did not correspond with any of the fields for the movie object

Related

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.

Issues with URL conf in Django

So I'm working on a project that displays titles of and songs and albums released by a particular artiste from a database. I'm kinda stuck. I'm trying to create a page that displays the songs in an album when you click on the album link. When the link is clicked, I want the URL to display the name of the artiste and the title of the album but i keep getting served with the same error. It is matching the name of the album with artiste names.
How do I make the page display the songs in the album.
Here's the codes for views
def home(request):
artistes = Artiste.objects.all()
return render(request, 'music/home.html', locals())
def details(request, artiste):
artistes = get_object_or_404(Artiste, name=artiste)
album = Artiste.objects.get(name=artiste).album_set.all()
single = Artiste.objects.get(name=artiste).song_set.filter(single=True)
return render(request, 'music/details.html', {'artistes': artistes, 'single': single, 'album':album})
def album_details(request,name,album):
albums = get_object_or_404(Album, title=album)
artistes = get_object_or_404(Artiste, name=name)
single = Album.objects.get(title=album).song_set.filter(single=False)
return render(request, 'music/album_detail.html', {'albums': albums, 'single': single})
url patterns
app_name = 'music'
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^(?P<artiste>.+)/$', views.details, name='details'),
url(r'^(?P<name>.+)/(?P<album>.+)/$', views.album_details, name='album_details')
]
album details page
<body>
{% if artistes.album_set.all %}
{% for songs in album %}
<h4>Albums</h4>
<!--<img src="{{album.art}}"><br>
-->
{{songs.title}}
<h5>{{songs.artiste}}</h5>
<h5>{{songs.title}}</h5>
{% endfor %}
{% else %}
<h3>No albums available</h3>
<h5>Check Out Songs </h5>
<ul>
{% for song in artistes.song_set.all %}
<li>{{song}} - mp3</li>
{% endfor %}
</ul>
{% endif %}
</body>
</html>
Your URLs are too generic. .+ matches everything, including things like "Wizked/Starboy" which you intended to be caught by the album_details URL.
You can fix this by switching the order of those URL patterns, but you should also make them less generic - eg r'^(?P<artiste>\w+) etc.
The code seems OK. Is a Logical problem.
The error is: No artiste maching this query.
in the URLS, the matched url is:
url(r'^(?P< artiste >.+)/$', views.details, name='details'),
Why? becouse ".+" matches everything, including "Wizkid/Starboy"
When you arrive to this code:
albums = get_object_or_404(Album, title=album)
album is equals to "Wizkid/Starboy"
The query raises a 404 becouse no item was found.
if you change in the url the ".+" with "\w+" as Daniel Said the match would be:
url(r'^(?P< name>.+)/(?P< album>.+)/$', views.album_details, name='album_details')
Then the params would be:
name = Wizkid
album = Starboy
Then you execute the code:
albums = get_object_or_404(Album, title=album)
artistes = get_object_or_404(Artiste, name=name)
If there are records in the database with albums and artists with that name, the page shows up.
Is not you still have the 404.
I suggest you to change at least the albums query to:
albums = Album.objects.filter(title=album)
In the html you can do:
{% for songs in album %}
<h4>Albums</h4>
<!--<img src="{{album.art}}"><br>
-->
{{songs.title}}
<h5>{{songs.artiste}}</h5>
<h5>{{songs.title}}</h5>
{% empty %}
No album was found
{% endfor %}
This way you can have a page with an artist with no albums

Getting a unexpected link in django template

I'm practicing a simple blog site, where if I clicked in author names, it shows the associated post! If I used two different view function the output is fine but if I implemented in one function, in author's post page it shows a url which should not! The screenshot of the html page:
The Url Link contain author post page link! but according to the code it should display the post link!
Url Link
I'm pasting my all code for better understanding. Thanks in advance!
This is my urls.py:
urlpatterns = [
url('^$', views.url_list, name='url_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$',
views.post_details, name = 'post_links'),
# url(r'^author/(?P<author_slug>[-\w]+)/$', views.author_posts, name = 'url_list_by_author'),
url(r'^author/(?P<author_slug>[-\w]+)/$', views.post_details, name = 'url_list_by_author'),
]
and my view.py is:
def post_details(request, year=None, month=None, day=None, post=None, author_slug=None):
author_post_list = None
if year:
post = get_object_or_404(UrlPost, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day,
)
if author_slug:
author_post_list = UrlPost.author_manager.author_post(author_slug)
post = None
return render(request, 'detail.html', {'post': post, 'author_post_list': author_post_list})
and html page:
{% extends "base.html" %}
{% block title %}{{post.title}}{% endblock %}
{% block content %}
<h1>{{ post.title|title }}</h1>
<p>{{ post.publish }}</p>
<ul>
{% for author in post.author.all %}
{% if forloop.first %}
<li><h4>Author: </h4></li>
{% endif %}
<li><h4>{{ author|title }}</h4></li>
{% if not forloop.last %}
<li><h4>, </h4></li>
{% endif %}
{% endfor %}
</ul>
<p>{{ post.description }}</p>
Url Link
{% include "author_post.html" %}
{% endblock %}
The first 'url link' you see at the top comes from this line in your html template:
Url Link
All the rest of what is displayed comes from the author_post.html template. The url link is not "additional", actually it's just that everything before is missing.
Probably because the post variable is None. If you actually inspect the generated html, it will look like this:
<h1></h1>
<p></p>
<ul>
</ul>
<p></p>
Url Link
(and the here you will have the contents of author_post)
OK, now for how to solve this: you should not use the same view to display the post and the post author's post. You should create two separate views. Each with its template. Then, assuming you named the new view author_posts in your urls.py:
urlpatterns = [
url('^$', views.url_list, name='url_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$',
views.post_details, name = 'post_links'),
url(r'^author/(?P<author_slug>[-\w]+)/$', views.author_posts, name = 'url_list_by_author'),
]

populate bootstrap dropdown on the base.html using django

Im using django 1.9 and python 3.5 which i'm both really new too, and i'm having trouble populating a bootstrap dropdown which is located in the base.html.
So far i have this:
base.html:
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Events
<b class="caret"></b></a>
<ul class="dropdown-menu">
{% if categories %}
{% for cat in category %}
<li><a href="{% url 'categories' pk=cat.pk %}">
{{ cat.name }}</a></li>
{% endfor %}
{% else %}
There are no categories present.
{% endif %}
</ul>
</li>
views.py:
def categories(request, pk):
category = Category.objects.get(pk=pk)
return render(request, 'categories.html', {'category': category})
urls.py:
url(r'^categories/(?P<pk>\d+)/$', views.categories, name='categories'),
So i want the drop down to display the available categories from the database and then when i click on one it will obviously load up the categories.html displaying the relevant category.
any help would be much appreciated.
Edit: sorry i forgot to say the problem i am having.
Im not getting the drop down populated, and is only giving me the "there is no categories present"
There are a couple of issues here:
Firstly, you don't have any context in your view called categories, yet you're checking for them in your template. Your view function is called 'categories', which might be creating some confusion for you. However, this is not context that is accessible to your view. It's just a function.
Secondly, you're not getting a list of categories (which you could iterate as you are in your template) in your view, you're getting a single category with:
category = Category.objects.get(pk=pk)
# using the get() method means you're requesting a single object
So you need to do something more like:
categories = Category.objects.all()
# here, we're getting a QuerySet (list of objects), rather a single object
Then add the categories to your context. So your view would end up looking like this:
def categories(request, pk):
categories = Category.objects.all()
return render(request, 'categories.html', {'categories': categories})
Also, you'll need to change your iterator to iterate over categories, not category:
{% for cat in categories %}
<li><a href="{% url 'categories' pk=cat.pk %}">
{{ cat.name }}</a></li>
{% endfor %}
So, "categories" variable will never give you "true", while you do not define it, and add it to template context.
Do this in your python code
def categories(request, pk):
categories = Category.objects.all()
return render(request, 'categories.html', {'categories': categories})

Django: Named URLs / Same Template, Different Named URL

I have a webapp that lists all of my artists, albums and songs when the appropriate link is clicked. I make extensive use of generic views (object_list/detail) and named urls but I am coming across an annoyance. I have three templates that pretty much output the exact same html that look just like this:
{% extends "base.html" %}
{% block content %}
<div id="content">
<ul id="starts-with">
{% for starts_with in starts_with_list %}
<li>{{ starts_with|upper }}</li>
{% endfor %}
</ul>
<ul>
{% for song in songs_list %}
<li>{{ song.title }}</li>
{% endfor %}
</ul>
</div>
{% endblock content %}
My artist and album template look pretty much the same and I'd like to combine the three template's into one. The fact that my variables start with song can easily be changed to the default obj. It's my <ul id="starts-with"> named url I don't know how to correct. Obviously I want it to link to a specific album/artist/song using the named urls in my urls.py but I don't know how to make it context aware. Any suggestions?
urls.py:
urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
# (r'^$', index),
url(r'^artists/$', artist_list, name='artist_list'),
url(r'^artists/(?P<starts_with>\w)/$', artist_list, name='artist_list_x'),
url(r'^artist/(?P<artist_id>\d+)/$', artist_detail, name='artist_detail'),
url(r'^albums/$', album_list, name='album_list'),
url(r'^albums/(?P<starts_with>\w)/$', album_list, name='album_list_x'),
url(r'^album/(?P<album_id>\w)/$', album_detail, name='album_detail'),
url(r'^songs/$', song_list, name='song_list'),
url(r'^songs/(?P<starts_with>\w)/$', song_list, name='song_list_x'),
url(r'^song/(?P<song_id>\w)/$', song_detail, name='song_detail'),
)
You could define url patterns for a generic object_type instead of individually for artists, albums and songs:
urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
# (r'^$', index),
url(r'^(?P<object_type>\w+)/$', music_object_list, name='music_object_list'),
url(r'^(?P<object_type>\w+)/(?P<starts_with>\w)/$', music_object_list, name='music_object_list_x'),
url(r'^(?P<object_type>\w+)/(?P<object_id>\d+)/$', music_object_detail, name='music_object_detail'),
)
Then in your template, your url tag becomes
{% url music_object_list_x object_type starts_with %} *
You may find you only need one view, music_object_list. If you find you need different functions for each object type, then call the individual functions in music_object_list.
def music_object_list(request, object_type, starts_with=None):
if object_type == 'artists':
return artist_list(request, starts_with=starts_with)
elif object_type == 'albums':
return album_list(request, starts_with=starts_with)
...
If you are using django.views.generic.list_detail.object_list, then remember to add object_type to the extra_context dictionary. This will add object_type to the template context, allowing the url tag to work.
extra_context = {'object_type': 'songs', ...}
* This is the new url tag syntax for Django 1.2. For older versions you would use a comma.
{% url music_object_list_x object_type,starts_with %}
See the docs (Current, 1.1) for more information

Categories

Resources