Using Django, I'm looking for a way to use one url patern (with slug) to query one model and if nothing is found query a second model. I'm using Class Based Views.
I am following this answer, and the next View is being called. But then I get the following error:
"Generic detail view must be called with either an object pk or a slug."
I can't figure out how to pass the slug to the next View.
My url:
url(r'^(?P<slug>[-\w]+)/$', SingleView.as_view(), name='singleview'),
My CBV's:
class SingleView(DetailView):
def dispatch(self, request, *args, **kwargs):
post_or_page_slug = kwargs.pop('slug')
if Page.objects.filter(slug=post_or_page_slug).count() != 0:
return PageDetailView.as_view()(request, *args, **kwargs)
elif Post.objects.filter(slug=post_or_page_slug).count() != 0:
return PostDetailView.as_view()(request, *args, **kwargs)
else:
raise Http404
class PageDetailView(DetailView):
model = Page
template_name = 'page-detail.html'
class PostDetailView(DetailView):
model = Post
template_name = 'post-detail.html'
The problem is that you are popping the slug, which removes it from kwargs. This means that the slug is not getting passed to the view.
You can change it to:
post_or_page_slug = kwargs.pop['slug']
I would usually discourage calling MyView.as_view(request, *args, **kwargs) inside another view. Class based views are intended to be extended by subclassing, not by calling them inside other views.
For the two views in your example, you could combine them into a single view by overriding get_object and get_template_names.
from django.http import Http404
class PageOrPostDetailView(DetailView):
def get_object(self):
for Model in [Page, Post]:
try:
object = Model.objects.get(slug=self.kwargs['slug'])
return object
except Model.DoesNotExist:
pass
raise Http404
def get_template_names(self):
if isinstance(self.object, Page):
return ['page-detail.html']
else:
return ['post-detail.html']