1

I have recently switched from Django 1.9 to 1.11.17 and one thing is bothering me a lot. There is this error that says

TypeError at /somepath
context must be a dict rather than Context

The line that is throwing it is:

return render(request=request, template_name="mytemplate.html", context={"form": form, "update": updateType})

There are many answers on SO where people use RequestContext or Context instead of dict for context and switching to dict solves their problem. But not for me. Here I am pretty sure that my context is in fact a dict. What is interesting if I change it to:

return render(request=request, template_name="mytemplate.html", context={})

The error goes away, but obviously causes another error later on. Do you guys have any idead on what am I doing wrong here?

EDIT: My imports:

from django.shortcuts import render, render_to_response
from django.template.context import RequestContext, Context

I have tried bot render and render_to_response with similar effect. Also using Context or RequestContext gave similar error.

EDIT2: More code for reference

from django.http import (
    HttpResponseRedirect,
    HttpResponseBadRequest,
)
from django.shortcuts import render, render_to_response
from django.template import RequestContext, Context
from django.utils.html import escape

# some more imports, but from local files, not django

def update_my_template(request):
    user = request.user
    # preform some checks for user
    ...

    if request.method == "GET":
        updateType = request.GET.get("id")
        if updateType:
            form = None
            if updateType == "something":
                form = SomeForm(user)
            if updateType == "something else":
                form = DifferentForm()
            if form is None:
                return HttpResponseRedirect("/somepage")

            # This was the code that worked in 1.9
            rctx = RequestContext(
                request, {"form": form, "update": updateType}
            )
            return render_to_response("mytemplate.html", rctx)



    # some different cases, but the error is thrown already
...

Neither of these work:

dictctx = {"form": form, "update": updateType}
return render(request=request, template_name="mytemplate.html", dictctx)

.

ctx = Context({"form": form, "update": updateType})
return render(request=request, template_name="mytemplate.html", ctx)

.

ctx = Context({"form": form, "update": updateType})
return render(request=request, template_name="mytemplate.html", ctx.flatten())

.

rctx = RequestContext(request, {"form": form, "update": updateType})
return render_to_response("mytemplate.html", rctx.flatten())
Alex W
  • 37,233
  • 13
  • 109
  • 109
Devligue
  • 413
  • 5
  • 16

3 Answers3

1

The render logic is different, depending on what you pass to render:

def render(self, context):
        "Display stage -- can be called many times"
        with context.render_context.push_state(self):
            if context.template is None:
                with context.bind_template(self):
                    context.template_name = self.name
                    return self._render(context)
            else:
                return self._render(context)

and it looks as though you may be able to change your parameter template_name to just be name but your object doesn't have a context.render_context value which is why it would be better to create and use an instance of a Context

https://docs.djangoproject.com/en/1.11/_modules/django/template/base/#Template.render

The docs show passing an actual instance of a Context so I recommend that you do that in your code instead of just passing a dict:

>>> from django.template import Context, Template
>>> template = Template("My name is {{ my_name }}.")

>>> context = Context({"my_name": "Adrian"})
>>> template.render(context)
"My name is Adrian."

>>> context = Context({"my_name": "Dolores"})
>>> template.render(context)

so the easiest way to fix your code would be something like this:

from django.template import Context
...
return render(request=request, template_name="mytemplate.html", context=Context({"form": form, "update": updateType}))
Alex W
  • 37,233
  • 13
  • 109
  • 109
  • I have tried this with no effect: ctx = Context({"form": form, "update": updateType}) return render(request=request, template_name="mytemplate.html", context=ctx) – Devligue Dec 06 '18 at 18:20
  • Have you seen [this](https://stackoverflow.com/questions/43787700/django-1-11-typeerror-context-must-be-a-dict-rather-than-context#answer-53042348) ? It basically says to call `.flatten()` on any of your `RequestContext` objects before passing them to render – Alex W Dec 06 '18 at 18:30
  • Yep, tried other answers already before asking mine :( Same error – Devligue Dec 06 '18 at 18:34
  • I suppose it must be some super silly mistake, because I have literally tried every possibility, and my code looks identical to the ones posted in other SO answers. – Devligue Dec 06 '18 at 18:36
  • Could you edit your answer and add as much code as you can from that file? The only thing I can think of is that it may be something else in the file – Alex W Dec 06 '18 at 18:39
  • Solved, If you are curious, see my answer :) Thanks for the effort! – Devligue Dec 06 '18 at 19:19
1

Ok, after some more digging (in "unresolved" questions) I found this gem. And yep, that was solution to my problem. Basically I had the line {{form|bootstrap}} in my mytemplate.html which was causing this.

Even better, updating the django-bootstrap-form to version 3.4 allowed me to keep the {{form|bootstrap}} and get rid of the error.

Devligue
  • 413
  • 5
  • 16
-1

Always pass the variables/values in parameters. But You give both at a same time. Try this as,...

return render(request=request, template_name="mytemplate.html", {"form": form, "update": updateType})

Or

context={"form": form, "update": updateType} return render(request=request, template_name="mytemplate.html",context)

Usama Nadeem
  • 128
  • 1
  • 5
  • I don't see the difference between your first solution and mine. Also I have tried the second one already, with no difference :/ – Devligue Dec 06 '18 at 18:19
  • @Devligue In my first solution I just passed tuple, whereas in my second one I just passed variable of tupletype, But unfortunately you passed both at a same time. It’s a logical error – Usama Nadeem Dec 06 '18 at 18:25
  • But you do see that you pass positional argument after keyword argument? This code can't be even run in python, it immediately throws me error – Devligue Dec 06 '18 at 18:30