[Answered ]-Django: TypeError: context must be a dict rather than str

2πŸ‘

βœ…

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.

πŸ‘€user1600649

0πŸ‘

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.

0πŸ‘

If your code throws an exception it will run return reverse('users:home') which yields str data type.

However django docs states clearly:

get_context_data(**kwargs)

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'))
πŸ‘€an0o0nym

0πŸ‘

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')
πŸ‘€StackPointer

Leave a comment