user2669081 user2669081 - 27 days ago 12
Python Question

Python 3.5 TypeError: a bytes-like object is required, not 'str' using truncate filter

I am trying to convert my Python Flask app from 2.7 to 3.5. I have a simple CMS system using SQLAlchemy where my pages are displayed on the Index page with title and content (which are truncated). That is where my issue is happening.

It returns my pages as a list and my content as a string. I tried to encode the "pages" but that returns another error because that is not allowed on a list object.

Error:

File "C:\Python35\lib\site-packages\jinja2\filters.py", line 481, in do_truncate
result = s[:length - len(end)].rsplit(' ', 1)[0]
TypeError: a bytes-like object is required, not 'str'


The route:

@app.route("/")
def main():
pages = db.session.query(Pages).all()
return render_template('index.html', title='Dashboard', pages=pages)


index.html page

{% for page in pages %}
<div>
<a href="{{ url_for('view_page', page_id=page.id) }}"><h3>{{ page.title|truncate(150) }}</h3></a>
<p>{{ page.content|truncate(450)|striptags }}</p>
</div>
{% endfor %}

Answer

The error is caused by page.title being a bytes object. You can't use bytes.rsplit() with a str value (which is what truncate does). The truncate filter only supports str Unicode values.

You'll have to make sure pages.title is a unicode str object instead. Do so either by decoding in the template, or by defining the title field to be a Unicode string rather than bytes in your model and database.

Decoding in the template can be done with:

{{ page.title.decode('utf8')|truncate(150) }}

provided your data is actually UTF-8 encoded.

This wasn't an issue in Python 2 as there bytestrings are silently converted to unicode strings as needed (and provided they can be decoded).