3
votes

Hey I have been struggling with this one alot now. I am trying to pass my user objects to a template so that I can list them, or list usernames. Thanks to the help I've got from here so far I have this.

from django.template import Library, Node, Template, VariableDoesNotExist,      TemplateSyntaxError, \
                        Variable
from django.utils.translation import ugettext as _
from django.contrib.auth.models import User
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import models

register = Library()

class GetAllUsers(Node):
    def __init__(self, varname):
        # Save the variable that we will assigning the users to
        self.varname = varname
    def render(self, context):
        # Save all the user objects to the variable and return the context to the  template
        context[self.varname] = User.objects.all()
        return ''

@register.tag(name="get_all_users") 
def get_all_users(parser, token):
    # First break up the arguments that have been passed to the template tag
    bits = token.contents.split()
    if len(bits) != 3:
        raise TemplateSyntaxError, "get_all_users tag takes exactly 2 arguments"
    if bits[1] != 'as':
        raise TemplateSyntaxError, "1st argument to get_all_users tag must be 'as'"
    return GetAllUsers(bits)

#register.tag('get_all_users', get_all_users)

When I use this code with

{% load getusers %} 
{% get_all_users as allusers %}
{% for user in allusers %}
     {{ user }}
{% endfor %}

In my template I get Caught TypeError while rendering: unhashable type: 'list'. And it is specifically {% get_all_users as allusers %} thats causing it. I tried {% for user in get_all_users %}, it goes through but doesn't print anything.

Traceback

Traceback:
File "/usr/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)
File "/home/ajunkkil/Django/basedraft/messages/views.py" in compose
  91.     }, context_instance=RequestContext(request))
File "/usr/lib/python2.7/site-packages/django/shortcuts/__init__.py" in render_to_response
  20.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/usr/lib/python2.7/site-packages/django/template/loader.py" in render_to_string
  188.         return t.render(context_instance)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in render
  123.             return self._render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in _render
  117.         return self.nodelist.render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in render
  744.                 bits.append(self.render_node(node, context))
File "/usr/lib/python2.7/site-packages/django/template/debug.py" in render_node
  73.             result = node.render(context)
File "/usr/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  127.         return compiled_parent._render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in _render
  117.         return self.nodelist.render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in render
  744.                 bits.append(self.render_node(node, context))
File "/usr/lib/python2.7/site-packages/django/template/debug.py" in render_node
  73.             result = node.render(context)
File "/usr/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  127.         return compiled_parent._render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in _render
  117.         return self.nodelist.render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in render
  744.                 bits.append(self.render_node(node, context))
File "/usr/lib/python2.7/site-packages/django/template/debug.py" in render_node
  73.             result = node.render(context)
File "/usr/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  64.             result = block.nodelist.render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in render
  744.                 bits.append(self.render_node(node, context))
File "/usr/lib/python2.7/site-packages/django/template/debug.py" in render_node
  73.             result = node.render(context)
File "/usr/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  64.             result = block.nodelist.render(context)
File "/usr/lib/python2.7/site-packages/django/template/base.py" in render
  744.                 bits.append(self.render_node(node, context))
File "/usr/lib/python2.7/site-packages/django/template/debug.py" in render_node
  73.             result = node.render(context)
File "/home/ajunkkil/Django/basedraft/messages/templatetags/getusers.py" in render
  19.         context[self.varname] = User.objects.all()
File "/usr/lib/python2.7/site-packages/django/template/context.py" in __setitem__
  53.         self.dicts[-1][key] = value

Exception Type: TemplateSyntaxError at /messages/compose/
Exception Value: Caught TypeError while rendering: unhashable type: 'list'
3
Does it have to be in all templates or just in one?programmersbook
Just in one, Its a template for composing a new message and I would like to have the userlist there with it.leffe

3 Answers

3
votes

If you're using the latest development version, there's a new tag shortcut, assignment tags, which does all this for you. Then you could just do:

@register.assignment_tag
def get_all_users():
    return User.objects.all()

The actual problem with your code though is that you're passing the whole list of arguments to the tag instantiation:

return GetAllUsers(bits)

when you should just be passing the bit that contains the variable name:

return GetAllUsers(bits[2])

Finally, however, if this is just for one template, I don't understand why you're not doing it in the view, as programmersbook recommends.

0
votes

When maybe is better to do it over the context, don't see a point to use a tag

view:

from django.contrib.auth.models import User
from django.shortcuts               import render_to_response

def users(request):
    user_list = User.objects.all()

    ctx = {'user_list':user_list}

    render_to_response('temp.html', ctx)

in template:

{% for user in user_list %}
    {{ user }}
{% endfor %}
0
votes

Have you tried using an inclusion tag?

From what i understand it seems to sit between a simple tag and the assignment tag Daniel mentioned. That means the data isn't output directly as simple tags do. And where an assignment tag stores the data in variable which you directly iterate the inclusion tags needs a template snippet for rendering the data.

@register.inclusion_tag('users.html')
def show_users():
    users = user.objects.all()
    return {'users': users}

Then you can write a template snippet (users.html) that exactly renders your user list part.