sqlalchemy: злоупотребление временными полями - PullRequest
1 голос
/ 28 ноября 2011

У меня есть структура данных, которая объявляет такие отношения (псевдокод):

class User:
    ...
class Rating:
    rater = User
    post = Post
class Post:
    ratings = hasmany(Rating)
    page_id = ...

Я создаю веб-сайт с использованием этих моделей, и я буду ленивым, поэтому я передаю свой шаблон текущему зарегистрированному пользователю и кучу сообщений на текущей странице. На моей странице нужно знать, какой рейтинг вошедший в систему пользователь дал каждому сообщению, поэтому я использую функцию SQLAlchemy «один экземпляр на сеанс»:

posts = session.query(Post).filter(Post.page_id==current_pageid)
ratings = session.query(Post, Rating)\
    .filter(Rating.rater==user.id)\
    .filter(Post.page_id==current_pageid)
for post in posts:
    post.user_rating = None # default value
for post, rating in ratings:
    post.user_rating = rating

Затем я передаю свой шаблон в список сообщений. Это ужасно ужасная практика? Могу ли я сделать это лучше?

Ответы [ 2 ]

1 голос
/ 28 ноября 2011

Да, это плохая практика. И это даже может (в теории) победить вас в какой-то момент, например, когда вы запрашиваете из того же сеанса, не очищая его для некоторого поста, SQLAlchemy вернет вам тот же кэшированный объект с уже заполненным рейтингом для некоторого пользователя, не связанного с текущим контекстом. На практике это поможет найти в большинстве случаев.

Почему бы просто не передать список (post, rating) пар в шаблон? Большинство современных шаблонизаторов, доступных для Python, могут перебирать список пар.

Кстати, вы можете получать как сообщения, так и оценки одним запросом (объект рейтинга будет None для ВНЕШНЕГО СОЕДИНЕНИЯ, если он отсутствует):

session.query(Post, Rating).select_from(Post)\
    .outerjoin(Rating, (Post.id==Rating.post_id) & (Rating.rater==…))\
    .filter(Post.page_id==…)
1 голос
/ 28 ноября 2011

То, что вы делаете, достаточно хорошо, за исключением того, что в вашем запросе отсутствует предложение WHERE между Post и Rating:

# ...
.filter(Post.id==Rating.post_id)\

Но вы также можете получить результат в одномquery:

qry =  (session.query(Post, Rating).
        outerjoin(Rating, and_(Post.id==Rating.post_id, Rating.user_id==user.id)).
        filter(Post.page_id==current_pageid)
        )
res = qry.all() # you can return *res* already to a view, but to get to your results, do below as well:
for post, rating in res:
    post.user_rating = rating
posts = [post for post, rating in res]
return posts

Обратите внимание, что в вашем случае posts на самом деле не список, а запрос, и если вы выполните итерацию по нему во второй раз, вы можете потерять атрибут user_rating.Вы должны быть осторожны при возвращении связанных с сеансом объектов, таких как запрос к представлению.Более безопасно возвращать списки, как в том же коде выше.Чтобы исправить свой код, просто добавьте .all() к запросу:

posts = session.query(Post).filter(Post.page_id==current_pageid).all()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...