Reputation: 347
I wanto to redirect to an url if the object of GroupMember doesn't exist but shows this error:
TypeError: context must be a dict rather than str.
Here is my view:
class GroupDetail(DetailView):
template_name = "group_detail.html"
model = Group
def get_context_data(self, **kwargs):
context = super(GroupDetail, self).get_context_data(**kwargs)
# Code
try:
group_member = GroupMember.objects.get(member=volunteer, group=group)
context['group_member'] = group_member
# Code
return context
except:
return reverse('users:home')
I try with redirect and reverse_lazy but shows the same error and I tried with
reverse('users:home', {}), reverse('users:home', kwargs={})
and
reverse('users:home', kwargs=None)
Upvotes: 1
Views: 4721
Reputation: 11
I had this error because I forgot to put 'name=' in the view name.
path('listview/', BookListView.as_view(), 'book_list_view')
instead of
path('listview/', BookListView.as_view(), name='book_list_view')
Upvotes: 1
Reputation: 150178
The get_context_data()
method must return a dictionary representing the template context, not a URL string. To redirect on an exception you could override the get()
method instead:
from django.http HttpResponseRedirect
class GroupDetail(DetailView):
template_name = "group_detail.html"
model = Group
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
try:
# your code
return self.render_to_response(context)
except:
return HttpResponseRedirect(reverse("users:home"))
You can check the source code of DetailView
and its ancestors here.
Upvotes: 0
Reputation:
First, this always goes wrong, because there is no member or volunteer in the local data.
Secondly, the proper way to do this is to return None or an empty dict and override render_to_response
:
from django.views.generic import DetailView
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.messages import warning
class GroupDetail(DetailView):
def get_context_data(self, **kwargs):
volunteer = self.get_volunteer() # Or something like that
group = self.get_group() # Or something like that
try:
group_member = GroupMember.objects.get(
member=volunteer, group=group
)
return super(GroupDetail, self).get_context_data(
group_member=group_member, **kwargs
)
except GroupMember.DoesNotExist:
return None
# All other exceptions should really be raised as they are
# actual application errors.
def render_to_response(self, context, **response_kwargs):
if context is None:
warning(self.request, 'You are groupless! Peer pressure incoming.')
return HttpResponseRedirect(reverse("users:home"))
return super(GroupDetail, self).render_to_response(
context, **response_kwargs
)
This way, you make full use of the API and can extend and override the bit you need, which is why Class Based Views were designed.
Upvotes: 2
Reputation: 1516
If your code throws an exception it will run return reverse('users:home')
which yields str
data type.
However django docs states clearly:
Returns a dictionary representing the template context.
You need to do something like that:
def get_context_data(self, **kwargs):
context = super(GroupDetail, self).get_context_data(**kwargs)
# Code
try:
group_member = GroupMember.objects.get(member=volunteer,group=group)
context['group_member'] = group_member
# Code
finally:
return context
or you could do this if you want to redirect:
def get_context_data(self, **kwargs):
context = super(GroupDetail, self).get_context_data(**kwargs)
# Code
try:
group_member = GroupMember.objects.get(member=volunteer,group=group)
context['group_member'] = group_member
# Code
except:
return HttpResponseRedirect(reverse('users:home'))
Upvotes: 0