This commit is contained in:
parent
5b211c349e
commit
751f3de4b1
|
@ -30,52 +30,44 @@ from utils.logger import root_logger as logger
|
||||||
def query_shouts(slug=None, shout_id=None):
|
def query_shouts(slug=None, shout_id=None):
|
||||||
"""
|
"""
|
||||||
Базовый запрос для получения публикаций с подзапросами статистики, авторов и тем,
|
Базовый запрос для получения публикаций с подзапросами статистики, авторов и тем,
|
||||||
с агрегацией в строку.
|
с агрегированием в JSON.
|
||||||
|
|
||||||
:param slug: Опциональный параметр для фильтрации по slug.
|
|
||||||
:param shout_id: Опциональный параметр для фильтрации по shout_id.
|
|
||||||
:return: Запрос для получения публикаций, aliased_reaction:
|
|
||||||
"""
|
"""
|
||||||
aliased_reaction = aliased(Reaction)
|
aliased_reaction = aliased(Reaction)
|
||||||
|
|
||||||
# Подзапрос для уникальных авторов, объединенных в строку
|
# Подзапрос для уникальных авторов, агрегированных в JSON
|
||||||
authors_subquery = (
|
authors_subquery = (
|
||||||
select(
|
select(
|
||||||
ShoutAuthor.shout.label("shout_id"),
|
ShoutAuthor.shout.label("shout_id"),
|
||||||
func.string_agg(
|
func.json_agg(
|
||||||
func.concat_ws(
|
func.json_build_object(
|
||||||
";",
|
"id",
|
||||||
func.concat("id:", Author.id),
|
Author.id,
|
||||||
func.concat("name:", Author.name),
|
"name",
|
||||||
func.concat("slug:", Author.slug),
|
Author.name,
|
||||||
func.concat("pic:", Author.pic),
|
"slug",
|
||||||
func.concat("caption:", ShoutAuthor.caption), # Добавлено поле caption
|
Author.slug,
|
||||||
),
|
"pic",
|
||||||
" | ",
|
Author.pic,
|
||||||
).label("authors"), # Используем символ | как разделитель
|
"caption",
|
||||||
|
ShoutAuthor.caption,
|
||||||
|
)
|
||||||
|
).label("authors"),
|
||||||
)
|
)
|
||||||
.join(Author, ShoutAuthor.author == Author.id)
|
.join(Author, ShoutAuthor.author == Author.id)
|
||||||
.group_by(ShoutAuthor.shout)
|
.group_by(ShoutAuthor.shout)
|
||||||
.subquery()
|
.subquery()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Подзапрос для уникальных тем, объединенных в строку (включая main_topic_slug)
|
# Подзапрос для уникальных тем, агрегированных в JSON
|
||||||
topics_subquery = (
|
topics_subquery = (
|
||||||
select(
|
select(
|
||||||
ShoutTopic.shout.label("shout_id"),
|
ShoutTopic.shout.label("shout_id"),
|
||||||
func.string_agg(
|
func.json_agg(
|
||||||
func.concat_ws(
|
func.json_build_object(
|
||||||
";",
|
"id", Topic.id, "title", Topic.title, "slug", Topic.slug, "is_main", ShoutTopic.main
|
||||||
func.concat("id:", Topic.id),
|
)
|
||||||
func.concat("title:", Topic.title),
|
).label("topics"),
|
||||||
func.concat("slug:", Topic.slug),
|
func.max(case((ShoutTopic.main.is_(True), Topic.slug))).label("main_topic_slug"),
|
||||||
func.concat("is_main:", ShoutTopic.main),
|
|
||||||
),
|
|
||||||
" | ",
|
|
||||||
).label("topics"), # Используем символ | как разделитель
|
|
||||||
func.max(case((ShoutTopic.main.is_(True), Topic.slug))).label(
|
|
||||||
"main_topic_slug"
|
|
||||||
), # Получение основного топика
|
|
||||||
)
|
)
|
||||||
.join(Topic, ShoutTopic.topic == Topic.id)
|
.join(Topic, ShoutTopic.topic == Topic.id)
|
||||||
.group_by(ShoutTopic.shout)
|
.group_by(ShoutTopic.shout)
|
||||||
|
@ -150,43 +142,6 @@ def query_shouts(slug=None, shout_id=None):
|
||||||
return q, aliased_reaction
|
return q, aliased_reaction
|
||||||
|
|
||||||
|
|
||||||
def parse_aggregated_string(aggregated_str, model_class):
|
|
||||||
"""
|
|
||||||
Преобразует строку, полученную из string_agg, обратно в список объектов.
|
|
||||||
|
|
||||||
:param aggregated_str: Строка, содержащая агрегированные данные.
|
|
||||||
:param model_class: Класс модели, экземпляры которой нужно создать.
|
|
||||||
:return: Список объектов модели.
|
|
||||||
"""
|
|
||||||
if not aggregated_str:
|
|
||||||
return []
|
|
||||||
|
|
||||||
items = []
|
|
||||||
for item_str in aggregated_str.split(" | "):
|
|
||||||
item_data = {}
|
|
||||||
for field in item_str.split(";"):
|
|
||||||
if ":" in field:
|
|
||||||
key, value = field.split(":", 1)
|
|
||||||
item_data[key] = value
|
|
||||||
else:
|
|
||||||
logger.error(f"Некорректный формат поля: {field}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Фильтрация item_data, чтобы использовать только допустимые поля модели
|
|
||||||
filtered_data = {k: v for k, v in item_data.items() if hasattr(model_class, k)}
|
|
||||||
|
|
||||||
# Создание экземпляра модели на основе фильтрованного словаря
|
|
||||||
item_object = model_class(**filtered_data)
|
|
||||||
|
|
||||||
# Добавление синтетического поля, если оно присутствует в item_data
|
|
||||||
if "is_main" in item_data:
|
|
||||||
item_object.is_main = item_data["is_main"] == "True" # Преобразование в логическое значение
|
|
||||||
|
|
||||||
items.append(item_object)
|
|
||||||
|
|
||||||
return items
|
|
||||||
|
|
||||||
|
|
||||||
def get_shouts_with_stats(q, limit, offset=0, author_id=None):
|
def get_shouts_with_stats(q, limit, offset=0, author_id=None):
|
||||||
"""
|
"""
|
||||||
Получение публикаций со статистикой, и подзапросами авторов и тем.
|
Получение публикаций со статистикой, и подзапросами авторов и тем.
|
||||||
|
@ -219,12 +174,13 @@ def get_shouts_with_stats(q, limit, offset=0, author_id=None):
|
||||||
# followers_stat,
|
# followers_stat,
|
||||||
rating_stat,
|
rating_stat,
|
||||||
last_reacted_at,
|
last_reacted_at,
|
||||||
authors,
|
authors_json,
|
||||||
topics,
|
topics_json,
|
||||||
main_topic_slug,
|
main_topic_slug,
|
||||||
] in results:
|
] in results:
|
||||||
shout.authors = parse_aggregated_string(authors, Author)
|
# Преобразование JSON данных в объекты
|
||||||
shout.topics = parse_aggregated_string(topics, Topic)
|
shout.authors = [Author(**author) for author in authors_json] if authors_json else []
|
||||||
|
shout.topics = [Topic(**topic) for topic in topics_json] if topics_json else []
|
||||||
shout.stat = {
|
shout.stat = {
|
||||||
"viewed": ViewedStorage.get_shout(shout.id),
|
"viewed": ViewedStorage.get_shout(shout.id),
|
||||||
# "followed": followers_stat or 0,
|
# "followed": followers_stat or 0,
|
||||||
|
@ -337,8 +293,8 @@ async def get_shout(_, _info, slug="", shout_id=0):
|
||||||
# followers_stat,
|
# followers_stat,
|
||||||
rating_stat,
|
rating_stat,
|
||||||
last_reaction_at,
|
last_reaction_at,
|
||||||
authors,
|
authors_json,
|
||||||
topics,
|
topics_json,
|
||||||
main_topic_slug,
|
main_topic_slug,
|
||||||
] = results
|
] = results
|
||||||
|
|
||||||
|
@ -350,10 +306,10 @@ async def get_shout(_, _info, slug="", shout_id=0):
|
||||||
}
|
}
|
||||||
|
|
||||||
# Преобразование строк в объекты Author без их создания
|
# Преобразование строк в объекты Author без их создания
|
||||||
shout.authors = parse_aggregated_string(authors, Author)
|
shout.authors = [Author(**author) for author in authors_json] if authors_json else []
|
||||||
|
|
||||||
# Преобразование строк в объекты Topic без их создания
|
# Преобразование строк в объекты Topic без их создания
|
||||||
shout.topics = parse_aggregated_string(topics, Topic)
|
shout.topics = [Topic(**topic) for topic in topics_json] if topics_json else []
|
||||||
|
|
||||||
# Добавляем основной топик, если он существует
|
# Добавляем основной топик, если он существует
|
||||||
shout.main_topic = main_topic_slug
|
shout.main_topic = main_topic_slug
|
||||||
|
|
Loading…
Reference in New Issue
Block a user