django calls the "listing" function even though I told it to use the "watchlist" function when handling the request which arises when going to the .../watchlist url. I can't find the problem. Here is the error:
File "/home/simon/Dokumente/cs50WebProgramming/commerce/auctions/views.py", line 103, in listing
listing_obj = AuctionListing.objects.get(id=int(listing_id))
ValueError: invalid literal for int() with base 10: 'watchlist'
urls.py
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("create", views.create_listing, name="create"),
path("after_create", views.after_create, name="after_create"),
path("<str:listing_id>", views.listing, name="listing"),
path("<str:listing_id>/bid", views.after_bid, name="after_bid"),
path("watchlist", views.watchlist, name="watchlist")
]
views.py
def listing(request, listing_id):
listing_obj = AuctionListing.objects.get(id=int(listing_id))
return render(request, "auctions/listing.html", {
"listing": listing_obj
})
def watchlist(request):
return render(request, "auctions/watchlist.html")
The problem is with the order of your URL paths. You have <str:listing_id> before watchlist which leads to any string path to be matched with <str:listing_id>. Simply re-order your paths and you should be fine:
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("create", views.create_listing, name="create"),
path("after_create", views.after_create, name="after_create"),
path("watchlist", views.watchlist, name="watchlist")
path("<str:listing_id>/bid", views.after_bid, name="after_bid"),
path("<str:listing_id>", views.listing, name="listing"),
]
This is because <str:listing_id> matches any string, including watchlist, and since watchlist is defined first, it will fire the listing view. You can change the order, but you can alo restrict the path to only accept ints:
urlpatterns = [
path('', views.index, name='index'),
path('login/', views.login_view, name='login'),
path('logout/', views.logout_view, name='logout'),
path('register/', views.register, name='register'),
path('create/', views.create_listing, name='create'),
path('after_create/', views.after_create, name='after_create'),
path('watchlist/', views.watchlist, name='watchlist'),
path('<int:listing_id>/', views.listing, name='listing'),
path('<int:listing_id>/bid/', views.after_bid, name='after_bid')
]
By using <int:…>, it will only fire for sequences of digits, furthermore using int is no longer necessary, since the value is automatically converted to an int:
from django.shortcuts import get_object_or_404
def listing(request, listing_id):
listing_obj = get_object_or_404(AuctionListing, id=listing_id)
return render(request, "auctions/listing.html", {
"listing": listing_obj
})
Note: It is often better to use
get_object_or_404(…)[Django-doc], then to use.get(…)[Django-doc] directly. In case the object does not exists, for example because the user altered the URL themselves, theget_object_or_404(…)will result in returning a HTTP 404 Not Found response, whereas using.get(…)will result in a HTTP 500 Server Error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With