Question

I am trying to display a link to the next and previous object according the title field using get_next_or_previous_by_FIELD. Django 1.6 is throwing me this error.

Error during template rendering 'str' object has no attribute 'attname'

Error occurs here in template.

{% with next_lesson=lesson.get_next_by_title %}

And here in my models.

return self._get_next_or_previous_by_FIELD('title', is_next=True)

Here is my model.

class LessonManager(models.Manager):
    def all(self):
        return super(LessonManager, self).filter(active=True)

class Lesson(models.Model):
    active = models.BooleanField(default=False)
    title = models.CharField(max_length=65)
    slug = models.SlugField(unique=True)

    objects = LessonManager()

    def __unicode__(self, ):
        return self.title

    class Meta:
        ordering = ['title']

    def get_absolute_url(self):
        return reverse('lesson', args=[str(self.slug)])

    def get_next_by_title(self):
        try:
            return self._get_next_or_previous_by_FIELD('title', is_next=True)
        except Lesson.DoesNotExist:
            return None

    def get_previous_by_title(self):
        try:
            return self._get_next_or_previous_by_FIELD(order='title', is_next=False)
        except Lesson.DoesNotExist:
            return None

And here is my template.

<a class="col-md-6" href="{{ lesson.get_previous_by_title.get_absolute_url }}" title="{% trans "View previous post" %}">&laquo; {{ lesson.get_previous_by_title.title }}</a>
<a class="col-md-6" href="{{ lesson.get_next_by_title.get_absolute_url }}" title="{% trans "View previous post" %}">&laquo; {{ lesson.get_next_by_title.title }}</a>

Here is the full traceback as requested.

Environment:


Request Method: GET
Request URL: /tutorials/lesson/lesson-name/

Django Version: 1.6.2
Python Version: 2.7.6
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'blog',
 'ckeditor',
 'tutorials')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')
Template error:
In template C:\Users\Shaun\Desktop\sg\static\templates\tutorials\lesson.html, error at line 22
   'str' object has no attribute 'attname'
   12 :     {% endif %}


   13 :     {% if lesson.get_next_by_timestamp %}


   14 :         <a class="right" href="{{ lesson.get_next_post.get_absolute_url }}">{{ lesson.get_next_post.title|truncatewords:'4' }} &raquo;</a>


   15 :     {% endif %}


   16 : 


   17 :     <div class='clearfix'></div>


   18 : 


   19 :     <h2>{{ lesson.title|upper }}</h2>


   20 :     <p>{{ lesson.content|safe }}</p>


   21 :     


   22 :     <a class="col-md-6" href=" {{ lesson.get_previous_by_title.get_absolute_url }} " title="{% trans "View previous post" %}">&laquo; {{ lesson.get_previous_by_title.title }}</a>


   23 :   <a class="col-md-6" href="{{ lesson.get_next_by_title.get_absolute_url }}" title="{% trans "View previous post" %}">&laquo; {{ lesson.get_next_by_title.title }}</a>


   24 : 


   25 : {% endblock %}

Traceback:
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\core\handlers\base.py" in get_response
  114.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Shaun\Desktop\sg\src\tutorials\views.py" in single_lesson
  13.     return render_to_response('tutorials/lesson.html', locals(), context_instance=RequestContext(request))
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\shortcuts\__init__.py" in render_to_response
  29.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\loader.py" in render_to_string
  169.         return t.render(context_instance)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in render
  140.             return self._render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in _render
  134.         return self.nodelist.render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in render
  840.                 bit = self.render_node(node, context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\debug.py" in render_node
  78.             return node.render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\loader_tags.py" in render
  123.         return compiled_parent._render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in _render
  134.         return self.nodelist.render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in render
  840.                 bit = self.render_node(node, context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\debug.py" in render_node
  78.             return node.render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\loader_tags.py" in render
  62.             result = block.nodelist.render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in render
  840.                 bit = self.render_node(node, context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\debug.py" in render_node
  78.             return node.render(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\debug.py" in render
  88.             output = self.filter_expression.resolve(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in resolve
  585.                 obj = self.var.resolve(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in resolve
  735.             value = self._resolve_lookup(context)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\template\base.py" in _resolve_lookup
  789.                             current = current()
File "C:\Users\Shaun\Desktop\sg\src\tutorials\models.py" in get_previous_by_title
  64.             return self._get_next_or_previous_by_FIELD('title', is_next=False)
File "C:\Users\Shaun\Desktop\sg\lib\site-packages\django\db\models\base.py" in _get_next_or_previous_by_FIELD
  708.         param = force_text(getattr(self, field.attname))

Exception Type: AttributeError at /tutorials/lesson/setting-up-your-django-blog-application/
Exception Value: 'str' object has no attribute 'attname'
Was it helpful?

Solution

_get_next_or_previous_by_FIELD isn't supposed to be something you call yourself.

The main problem you're having is that it is expecting a Field object, not a string, hence the error. This is because the method is actually used as part of a curried function that is created by the field class itself, which in turn is called by the model metaclass when the model is first imported.

The currying creates the actual get_next_by_foo and get_previous_by_foo methods. In fact, these are only created for Date and Datetime fields.

Note that the uncurried method name begins with an underscore, which - with the exception of Model._meta - is a good sign that you're not supposed to be using it in your own code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top