Оптимизация запросов ORM в Flask с использованием Flask -SQLAlchemy - PullRequest
0 голосов
/ 01 мая 2020

Я написал тот же проект, используя Django и Flask. Весь код доступен на моем аккаунте Github. Этот веб-сайт представляет собой небольшой веб-сайт с вопросами и ответами (в формате CTF с очень простыми вопросами) Вот ссылки:

Мой Вопрос касается оптимизации запросов ORM в SQLAlchemy или Flask -SQLAlchemy.

Я постараюсь написать схему таблиц так, как я могу, для лучшего понимания.

Teams (id, team_name, email, phone, password)
Questions (id, name, body, hint, answer, points, visible)
Submissions (id, team(fk), question(fk), timestamp)

Если кто-то из вас захочет увидеть действительный код, вот они:
Для Django - Вопрос и ответ , Команда
Для Flask - Вопрос , Команда , Отправка

Для двух маршрутов /submissions и /leaderboard мне пришлось написать определенные запросы, используя ОРМ. Вот как выглядят страницы: leaderboard submissions

Для Django запросы выглядят довольно хорошо (или, по крайней мере, я так думаю: P)

def submissions(request):
    all_submissions = Question.objects \
        .values('id', 'name') \
        .order_by('id') \
        .annotate(submissions=Count('submission'))

    print(all_submissions.query)

    return render(request, 'questions/submissions.html', {
        'submissions': all_submissions
    })

def leaderboard(request):
    team_scores = Team.objects \
        .values('team_name') \
        .order_by('team_name') \
        .annotate(score=Coalesce(Sum('submission__question__points'), 0)) \
        .order_by('-score')

    print(team_scores.query)

    return render(request, 'questions/leaderboard.html', {
        'team_scores': team_scores,
    })

И необработанные SQL запросы выглядят так:

SELECT "teams_team"."team_name", COALESCE(SUM("questions_question"."points"), 0) AS "score" FROM "teams_team" LEFT OUTER JOIN "questions_submission" ON ("teams_team"."id" = "questions_submission"."team_id") LEFT OUTER JOIN "questions_question" ON ("questions_submission"."question_id" = "questions_question"."id") GROUP BY "teams_team"."team_name" ORDER BY "score" DESC

SELECT "questions_question"."id", "questions_question"."name", COUNT("questions_submission"."id") AS "submissions" FROM "questions_question" LEFT OUTER JOIN "questions_submission" ON ("questions_question"."id" = "questions_submission"."question_id") GROUP BY "questions_question"."id", "questions_question"."name" ORDER BY "questions_question"."id" ASC

Это было очень длинное введение в мой вопрос.

Мой вопрос начинается здесь я не могу написать этот или аналогичные запросы с использованием SQLAlchemy ORM, а PyCharm не предоставляет правильное завершение кода / предложения для того же.

Для Flask, вот как выглядят мои функции например:

def get_team_score(team):
    team_submissions = Submission.query.filter_by(team_id=team.id)
    score = sum(
        submission.question.points
        for submission in team_submissions
    )

    return score

@question_blueprint.route('/submissions')
def submissions():
    all_submissions = [
        {
            'id': q.id,
            'name': q.name,
            'submissions': Submission.query.filter_by(question_id=q.id).count()
        }
        for q in Question.get()  # fetch all Question rows
    ]
    return render_template('submissions.html', **{
        'submissions': all_submissions
    })

@question_blueprint.route('/leaderboard')
def leaderboard():
    team_scores = [
        {
            'team_name': team.team_name,
            'score': get_team_score(team)
        }
        for team in Team.query.filter_by()
    ]
    return render_template('leaderboard.html', **{
        'team_scores': team_scores
    })

Запросы не оптимизированы, и я хотел бы знать, возможно ли написать элегантные запросы, такие как django -orm, без необходимости писать необработанные операторы SQL. И, если возможно, я хотел бы получить несколько оптимизированных запросов для этих двух маршрутов, упомянутых в этом вопросе.

Фу.

Ответы [ 2 ]

2 голосов
/ 02 мая 2020

Вы можете изменить свой код выше, например, thiis.

@question_blueprint.route('/leaderboard')
def leaderboard():
    team_scores =\
        Team.query.join(
            Submission,
        ).join(
            Question,
        ).with_entities(
            Team.team_name,
            func.sum(Question.points).label("score")
        ).all()

    return render_template('leaderboard.html', **{
        'team_scores': team_scores
    })

В этом фрагменте ниже вы присоединяетесь к команде -> Представление -> Вопрос, а также потому, что вам нужно только название команды и общее количество баллов на основе вопроса из за каждую отправляемую вами сумму вы просто должны with_entities .

@question_blueprint.route('/submissions')
def submissions():
    all_submissions = Question.query.join(
        Submission
    ).with_entities(
        Question.id,
        Question.name,
        func.count().label("submissions")
    ).all()

    return render_template('submissions.html', **{
        'submissions': all_submissions
    })

Чтобы запросить вопрос с отправкой, выполните аналогичный запрос, как я добавил выше, но вместо того, чтобы рассчитать нужную сумму посчитать строку, так что вы просто измените его в веселье c .sum

0 голосов
/ 02 мая 2020

После ответа Кельвина я понимаю, как мне нужно выполнять запросы в SQLAlchemy. Я продолжал изменять ответ Кельвина, чтобы он соответствовал моим потребностям, и эти запросы полностью работают.

@question_blueprint.route('/submissions')
def submissions():
    all_submissions = Question.query \
        .outerjoin(Submission) \
        .group_by(Question.id) \
        .order_by(Question.id) \
        .with_entities(
            Question.id,
            Question.name,
            func.count(Submission.id).label('submissions')) \
        .all()

    return render_template('submissions.html', **{
        'submissions': all_submissions
    })


@question_blueprint.route('/leaderboard')
def leaderboard():
    team_scores = Team.query \
        .outerjoin(Submission) \
        .outerjoin(Question) \
        .group_by(Team.team_name) \
        .with_entities(
            Team.team_name,
            func.coalesce(func.sum(Question.points), 0).label('score')) \
        .with_labels().all()

    return render_template('leaderboard.html', **{
        'team_scores': team_scores
    })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...