r'^(?P<pk>\d+)$ URL 404ing - django

I'm trying to use this link <a href="Annotation/{{ vod.id }}"> to load another page in my website base on primary key of videos. My url file is as follows:
urlpatterns = [
url(r'^$', ListView.as_view(queryset=Vod.objects.all().order_by("-date")[:25], template_name="Annotation/home.html")),
url(r'^(?P<pk>\d+)$', ListView.as_view(queryset=Vod.objects.get(pk=1).posts.all().order_by("-date"), template_name="Annotation/post.html")),
]
I get the standard 404 from the links generated using the aforementioned link.
Thanks!
edit: Added the base URLs
url(r'^admin/', admin.site.urls),
url(r'^Annotation', include('Annotation.urls')),
url(r'^Profile', include('Profile.urls')),
This is the URL for Profile.urls
url(r'^$', views.index, name='index'),
edit2: Changed URL and added view I'm trying to use.
url(r'^(?P<key>[0-9]+)$', views.post, name="post")
Here's views.post
def post(request, key):
try:
target_vod = Vod.objects.get(pk=key)
except Target.DoesNotExist:
raise Http404("Vod does not exist")
target_posts = Vod.objects.get(pk=key).posts.all().order_by("-date")
context = {'target_vod': target_vod, 'target_posts': target_posts}
return render(request, 'Annotation/post.html', context)

I have seperated the code and put it into a views.py. This should work.
urls.py
url(r'^(?P<pk>[0-9]+)$', AnnoList.as_view(), template_name="Annotation/post.html")),
Then in views.py:
class AnnoList(ListView):
template_name = 'Annotation/post.html'
def get_queryset(self):
self.vod = get_object_or_404(Vod, pk=self.args[0])
return Posts.objects.filter(vod=self.vod).all().order_by("-date")
I assuming here that you have two different tables and that Posts has a foreign key to Vod.

Related

Django Rest Framework routing with primary key prefix

I'm using DRF DefaultRouter as follows.
# urls.py
router = DefaultRouter()
router.register('book', BookingViewSet, basename='booking')
router.register('book/<int:bk>/reservation', ReservationViewSet, basename='reservation')
urlpatterns = [
path('', include(router.urls)),
]
# view
class ReservationViewSet(viewsets.ModelViewSet):
serializer_class = ReservationSerializer
queryset = Reservation.objects.all() # for testing only
But when I visit the URL /book/1/reservation/ it says no url pattern found.
lending/ ^book/<int:bk>/reservation/$ [name='reservation-list']
lending/ ^book/<int:bk>/reservation\.(?P<format>[a-z0-9]+)/?$ [name='reservation-list']
lending/ ^book/<int:bk>/reservation/(?P<pk>[^/.]+)/$ [name='reservation-detail']
lending/ ^book/<int:bk>/reservation/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='reservation-detail']
The current path, lending/book/1/reservation/, didn’t match any of these.
I'm using bk to capture book id.
That's because it implements the <int:bk> as regex, so without any interpretation. Probably the simplest way to do this is with two routers:
router1 = DefaultRouter()
router1.register('book', BookingViewSet, basename='booking')
router2 = DefaultRouter()
router2.register('reservation', ReservationViewSet, basename='reservation')
urlpatterns = [
path('', include(router1.urls)),
path('book/<int:bk>/', include(router2.urls)),
]
In the ReservationViewSet you can then for example filter with bk:
class ReservationViewSet(viewsets.ModelViewSet):
serializer_class = ReservationSerializer
def get_queryset(self):
return Reservation.objects.filter(book_id=self.kwargs['bk'])
Just wanted to add this to the accepted answer ... You can also do this with the same router, just embed the pk in the URL in regex form as the error message suggests:
# urls.py
router = DefaultRouter()
router.register('book', BookingViewSet, basename='booking')
router.register('book/(?P<bk>[^/.]+)/reservation', ReservationViewSet, basename='reservation')
urlpatterns = [
path('', include(router.urls)),
]
You can then access the bk argument in your view using self.kwargs['bk'].

list index out of range error from previous view when rendering a different view

Apologies if I'm missing something daft here but I'm new to Django and I can't work this out.
I'm creating a basic reddit style app focusing on cryptocurrency. I have a view which gets price data from an API and displays it as well as any posts specific to that coin:
views.py:
def coin_posts(request, id):
if request.method == 'GET':
coin_display = {}
post = Post.objects.filter(coin_name=id)
api = 'https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=%s&order=market_cap_desc&per_page=100&page=1&sparkline=false' % id
response = requests.get(api)
data = response.json()
coin = data[0]
coin_data = Coins(
coin_id = coin['id'],
coin_name = coin['name'],
coin_price = coin['current_price'],
market_cap = coin['market_cap'],
rank = coin['market_cap_rank'],
price_change = coin['price_change_24h'],
slug = coin['symbol'],
image_url = coin['image']
)
coin_data.save()
coin_display = Coins.objects.filter(coin_id=id)
return render(request, 'coins.html', {
'post': post,
'coin_display': coin_display,
'post_form': PostForm()
},
)
I want to be able to click on each post to view any comments related to said post, as I haven't got that far yet I just wish to be able to view that single post on another page. So each post has the following link on the template:
Comments
and here are the corresponding URLs and view:
urlpatterns = [
path('', views.index, name="index"),
path('<str:id>/', views.coin_posts, name='coin_posts'),
path('<slug:slug>/', views.post_detail, name='coin_detail'),
]
def post_detail(request, slug):
post = Post.objects.filter(slug=slug)
return render(request, 'coin_detail.html', {
'post': post,
},
)
The problem is when I click on the link, I get the error: list index out of range
Which is referencing the coin = data[0] in the first view.
I can see that it's trying to populate the database, but because there's no GET data there's no list to index. My question is why is that happening? If I've clicked a link which calls the post_detail function, why is it executing the code in the coin_posts function?
I think the problem is in the url paths. The path of coin_posts "str:id/" is equal to the path of post_detail 'slug:slug/'. The only difference between these two urls is that str will accept only string while slug will match any slug string consisting of ASCII letters or numbers, plus the hyphen and underscore characters (reference).
Try defferenciating the path adding a different path for example:
urlpatterns = [
path('', views.index, name="index"),
path('coin_posts/<str:id>/', views.coin_posts, name='coin_posts'),
path('post_detail/<slug:slug>/', views.post_detail, name='coin_detail'),
]

django redirect causes a redirect to next page, but then returns to original?

My redirect function is causing some issues. I call a url from a view using reverse with the parameters required for the view. There are no errors and in the browser of the url it correctly displays these parameters. However it seems like it redirects to the new url, but immediately after requesting the new view for the new url the page returns to the original view with the new url still displayed in the browser. Can anyone tell me if I am using the redirect function correctly or maybe I am using the reverse incorrectly?
P.S. I chopped out a lot of code because StackOverflow won't let me post all of it.
home/urls.py
from django.conf.urls import url
from home import views
app_name = 'home'
urlpatterns = [
url('^$', views.index, name='index'),
url('^patient_summary/patientid=(?P<patient_id>\d+)&clinicid=(?P<clinic_id>\d+)/', views.patient_summary, name='patient_summary'),
url('^patient_summary/patientid=(?P<patient_id>\d+)&clinicid=(?P<clinic_id>\d+)/careplanid=(?P<careplan_id>\d+)/', views.care_plan, name='care_plan'),
]
home/views.py
def patient_summary(request, token, patient_id, clinic_id):
user = get_user(token)
if request.method == "POST":
if ('careplanselected' in request.POST):
props = request.POST.get('careplan')
props = props.split("#")
CPID = props[0]
cpname = props[1]
my_dict = {'token': token, 'patient_id': patient_id, 'clinic_id': clinic_id, 'careplan_id': CPID}
return redirect(reverse('home:care_plan', kwargs=my_dict))
return render(request, 'home/patient_summary.html')
def care_plan(request, token, patient_id, clinic_id, careplan_id):
user = get_user(token)
care_plan = []
cpname = ''
return render(request, 'home/care_plan.html' )
Your URL patterns are missing dollars to mark the end of the URL. That means that your patient_summary view will be handling requests meant for the care_plan view.
Change the patterns to:
url('^patient_summary/patientid=(?P<patient_id>\d+)&clinicid=(?P<clinic_id>\d+)/$', views.patient_summary, name='patient_summary'),
url('^patient_summary/patientid=(?P<patient_id>\d+)&clinicid=(?P<clinic_id>\d+)/careplanid=(?P<careplan_id>\d+)/$', views.care_plan, name='care_plan'),

How to redirect url with added url parameters

I have a workout calendar app where if a user goes to /workoutcal, I want them to be redirected to workoutcal/<today's year>/<today's month>. That means I want them to be redirected to this route, should they go to /workoutcal:
url(r'^(?P<year>[0-9]+)/(?P<month>[1-9]|1[0-2])$', views.calendar, name='calendar'),
So how can I write a new url pattern in urls.py that does something like:
url(r'^$', RedirectView().as_view(url=reverse_lazy(),todays_year, todays_month)),
You can subclass RedirectView, override get_redirect_url, and reverse the url there.
class MonthRedirectView(RedirectView):
def get_redirect_url(*args, **kwargs):
today = timezone.now()
return reverse(calendar, args=[today.year, today.month])
Then include your view in the URL pattern:
url(r'^$', MonthRedirectView().as_view()),
I found another solution to my problem, which is making a view that simply calls the calendar with the right arguments:
the url:
url(r'^$', views.redirect_to_calendar),
the redirect view:
def redirect_to_calendar(request):
today = timezone.now()
return calendar(request, year = today.year, month = today.month)
the view we serve to the user:
def calendar(request, year = None, month = None):
## A bunch of server logic
return HttpResponse(template.render(context, request))
Assuming your RedirectView is in your app's urls.py:
url(r'^(?P<year>[0-9]+)/(?P<month>[1-9]|1[0-2])$', views.calendar, name='calendar'),
url(r'^$', RedirectView().as_view(url='{}/{}'.format(todays_year, todays_month)),
EDIT: This assumes that todays_year and todays_month are calculated when a user goes to /workoutcal/, which they aren't (they're loaded at URL load time). See Alasdair's answer.

Using multiple slugs in a url

I want to keep my urls dynamic as well as clean.
Therefore I'm using slugs.
My problem right now is, that I get the following error:
redefinition of group name 'slug' as group 2; was group 1 at position 42
I think I get that error, because I have two slugs in my chain.
For reference I have a ListView into ListView into an UpdateView, alls importet from django.views.generic. The first list view gives me the first slug and the update view the second.
Here is the url pattern (spread across the apps):
First list view:
urlpatterns = [
url(r'^$', RestaurantListView.as_view(), name='restaurant-list'),
url(r'^(?P<slug>[\w-]+)/menus/', include('menu.urls', namespace='menu')),
]
Second list view:
urlpatterns = [
url(r'^$', MenuListView.as_view(), name='menu-list'),
url(r'^(?P<slug>[\w-]+)/', MenuUpdateView.as_view(), name='menu-detail'),
]
In the templates I get the objects via:
<li><a href='{{obj.get_absolute_url}}'> {{obj}} </a></li>
Which I have defined in the respective models:
def get_absolute_url(self):
return reverse('restaurants:menu:menu-detail', kwargs={'slug': self.slug})
and
def get_absolute_url(self):
return reverse('restaurants:menu:menu-list', kwargs={'slug': self.slug})
So the resulting pattern at the end is:
restaurants/(?P<slug>[\w-]+)/menus/(?P<slug>[\w-]+)/
How can I fix it so that I don't get the error anymore?
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
for more details https://docs.djangoproject.com/en/1.11/topics/http/urls/