У меня большие трудности с репликацией результирующего набора с помощью SQLAlchemy, который я могу сгенерировать с помощью SQL. Большая проблема заключается в том, что мне трудно понять, как правильно создать специальный столбец, который можно вставить в качестве аргумента в query(). Во-вторых, меня смущают различия в целях и реализации между ORM и языком выражений.
Вот мои модели:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
sz_shirt_dress_sleeve = db.relationship(
'SizeKeyShirtDressSleeve', secondary=LinkUserSizeShirtDressSleeve, backref=db.backref('users', lazy='dynamic'))
LinkUserSizeShirtDressSleeve = db.Table(
'link_user_size_shirt_dress_sleeve',
db.Column('size_id', db.Integer, db.ForeignKey('size_key_shirt_dress_sleeve.id'), primary_key=True),
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True)
)
class SizeKeyShirtDressSleeve(db.Model):
id = db.Column(db.Integer, primary_key=True)
size = db.Column(db.Numeric(4,2))
Я пытаюсь реплицировать этот SQL:
SELECT
size,
case WHEN link_user_size_shirt_dress_sleeve.size_id IS NOT NULL
THEN 'true' ELSE 'false' END AS present
FROM size_key_shirt_dress_sleeve
LEFT JOIN link_user_size_shirt_dress_sleeve
ON size_key_shirt_dress_sleeve.id = link_user_size_shirt_dress_sleeve.size_id
;
Вещи, которые я пробовал, не сработали. (Если вы можете сделать вывод о каких-либо ошибочных мыслях, читая их, укажите на них.)
Настройка CASE
заранее:
case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)], else_=False)
query = db.session.query(SizeKeyShirtDressSleeve.size, case)
.outerjoin(LinkUserSizeShirtDressSleeve, SizeKeyShirtDressSleeve.id == LinkUserSizeShirtDressSleeve.size_id, )
.filter(LinkUserSizeShirtDressSleeve.id == 1)
Моя оболочка python ругается, что есть синтаксическая ошибка с else_=False
, хотя я считаю, что это так же, как оно представлено в документации для case:
>>> case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)], else_= False)
File "<stdin>", line 1
case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)], else_= False)
^
SyntaxError: invalid syntax
Если я пропущу else_
и выполню следующее:
case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)])
query = db.session.query(SizeKeyShirtDressSleeve.size, case)
.outerjoin(LinkUserSizeShirtDressSleeve, SizeKeyShirtDressSleeve.id == LinkUserSizeShirtDressSleeve.size_id, )
.filter(LinkUserSizeShirtDressSleeve.id == 1)
Я все еще ошибка:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/scoping.py", line 153, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 1399, in query
return self._query_cls(entities, self, **kwargs)
File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 140, in __init__
self._set_entities(entities)
File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 149, in _set_entities
entity_wrapper(self, ent)
File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 3999, in __init__
"expected - got '%r'" % (column, )
sqlalchemy.exc.InvalidRequestError: SQL expression, column, or mapped entity expected - got '[(<sqlalchemy.sql.elements.BinaryExpression object at 0x10f633240> True)]'
>>>
И я тоже не понимаю это сообщение об ошибке. Может ли это означать, что мне нужно обернуть случай в экземпляр Column
или column_literal
? Я не очень хорошо их понимаю, но я видел их в документах, и ошибка намекает на это. Хотя, боже, я бы хотел, чтобы это было просто формирование случая.
Контекст того, что я пытаюсь сделать:
Я пишу представление, которое будет генерировать страницу со списком всех размеров пользователя (в том числе рукава), а также всех возможных размеров (рукава) (пользователь может быть связан с несколькими размерами). Возможные размеры втулки варьируются от 30,0 до 38,0 с шагом 0,5.
Например, пользователь с идентификатором 1 связан с размерами 30.0
, 30.5
, 31.0
и 32.0
. В конечном итоге результирующий набор выглядит так (заголовки не нужны):
Size | UserIsAssociated
--------|-------------------
30.0 | True
30.5 | True
31.0 | True
31.5 | False
32.0 | True
32.5 | False
33.0 | False
...
38.0 | False
case
— это функция, вы должны вызвать ее и присвоить результат какому-то непересекающемуся имени:has_size = case([(...)], else_=...)
. Последняя ошибка означает, что вы не можете передать простой список из двух кортежей вQuery
как сущность.Кроме того, если вы хотите получить логическое значение на основе
size_id
, вам вообще не нужен регистр. Просто используйтеLinkUserSizeShirtDressSleeve.c.size_id != None
....правильно. case() — это функция. Вот это да. И мне это даже не понадобилось, чтобы получить логическое значение. Я думаю, что у меня есть то, что я хочу. Большое спасибо Илья!