(I'd tried to post this here, had someone post a version of it for me on r/flask, and am trying again here, so please excuse the duplication if the original one shows up.)
I'm trying to modify a Flask/SQLAlchemy app with what seems like a simple query, and it's throwing an error I can't figure out. I'm trying to retrieve some "author" records, to pass through to a template. Given an ID value, I'm joining two tables, in classes Author and Pseudonyms, that (I think) are properly declared. The function looks like:
def get_authors(author_id):
authors = Author.query.\
filter(Pseudonyms.author_id == Author.author_id).\
filter(Pseudonyms.pseudonym == author_id)
return authors
In the table declarations, the Author class has (among other things, of course, but I'm just identifying what's shown here):
pseudonyms = db.relationship("Pseudonyms")
and the Pseudonyms class has (likewise):
author_id = db.Column(db.Integer, db.ForeignKey('authors.author_id'))
I have a number of similar queries, with similarly-declared tables, that all work fine. This one, however, throws TypeError: expected string or bytes-like object, got 'type', with the stacktrace showing the second "filter" line in the above query as the most-immediate error line. But when I go to the console debugger, it shows that "author_id" is an int (substituting a literal integer value doesn't affect the error, BTW), and that "Pseudonyms.pseudonym" is also an integer type. I just don't know what's wrong with this line; and I don't see any other example of this "got 'type'" error anywhere, so don't know how to interpret it.
I've also tried rewriting this in the newer execute/select/where style, instead of query/filter, but it's the same. Everything I've tried always throws the "got 'type'" error in the second "filter" line (or its equivalent). I'm actually porting the query itself from raw SQL from a related app, but the problem is with this TypeError, not incorrect SQL or anything.
What am I missing?
Edit: As mentioned, I'm porting the query from raw SQL in a related app, where this query has been working fine for decades. The original query is:
query = """SELECT a.author_id, a.author_name
FROM authors a, pseudonyms p
WHERE p.pseudonym = %d
AND p.author_id = a.author_id""" % int(author_id)
Edit: added full traceback (with some changes to paths etc.):
Traceback (most recent call last):
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask/app.py", line 1536, in __call__
return self.wsgi_app(environ, start_response)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask/app.py", line 1514, in wsgi_app
response = self.handle_exception(e)
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask_caching/__init__.py", line 426, in decorated_function
rv = self._call_fn(f, *args, **kwargs)
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/flask_caching/__init__.py", line 185, in _call_fn
return ensure_sync(fn)(*args, **kwargs)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/path/to/app/python-port/app/views.py", line 228, in view_author
real_names=app.models.get_real_names_of_pseud(author),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/path/to/app/python-port/app/models.py", line 520, in get_real_names_of_pseud
return get_authors(author.author_id)
File "/path/to/app/python-port/app/models.py", line 477, in get_authors
filter(Pseudonyms.pseudonym == author_id).\
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/operators.py", line 584, in __eq__
return self.operate(eq, other)
~~~~~~~~~~~~^^^^^^^^^^^
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/elements.py", line 1515, in operate
return op(self.comparator, *other, **kwargs) # type: ignore[no-any-return] # noqa: E501
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/operators.py", line 584, in __eq__
return self.operate(eq, other)
~~~~~~~~~~~~^^^^^^^^^^^
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/type_api.py", line 197, in operate
return op_fn(self.expr, op, *other, **addtl_kw)
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/default_comparator.py", line 121, in _boolean_compare
obj = coercions.expect(
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/coercions.py", line 395, in expect
resolved = impl._literal_coercion(
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/coercions.py", line 803, in _literal_coercion
return expr._bind_param(operator, element, type_=bindparam_type)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/elements.py", line 4603, in _bind_param
return BindParameter(
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/elements.py", line 1978, in __init__
self.key = _anonymous_label.safe_construct(
File "/path/to/app/python-port/venv/lib/python3.13/site-packages/sqlalchemy/sql/elements.py", line 5471, in safe_construct
body = re.sub(r"[%\(\) \$]+", "_", body)
File "/usr/lib/python3.13/re/__init__.py", line 208, in sub
return _compile(pattern, flags).sub(repl, string, count)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
TypeError: expected string or bytes-like object, got 'type'
OP here. I have finally solved this, after a thorough debugging session where I started writing an MRE (at @snakecharmerb's suggestion).
In my class declaration of the Pseudonyms class, I originally had
pseudonym = db.column(db.Integer)
instead of the correct
pseudonym = db.Column(db.Integer)
And that was it.
@Detlef's code would have worked, if I had pasted it in instead of eyeballing it and missing the c/C distinction.
I suppose I would have expected some more clear error when I did this in the first place, or when I tried to use the pseudonym column, but so it goes. Thank you everyone for sticking with this.