如何在 Flask 中创建基于查询参数的搜索功能?

问题描述 投票:0回答:1

我正在学习针对 Web 开发人员的 Python 课程,目前正在处理 Flask。最近,我的讲师从我那里得到了一项任务,即借助查询参数为端点“/events”创建搜索功能。我几乎不知道我应该从什么开始,以及我是否应该在这种情况下使用 WTF-Forms。下面发布了更详细的代码(我的尝试)。

--->这是我的数据库:

class Event(db.Model):
    id = db.Column(db.Integer, primary_key=True, nullable=False)
    title = db.Column(db.Text, nullable=False)
    description = db.Column(db.Text, nullable=False)
    created_by = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
    begin_at = db.Column(db.Date, nullable=False)
    end_at = db.Column(db.Date, nullable=False)
    max_users = db.Column(db.Integer, nullable=False)
    is_active = db.Column(db.Boolean, default=False, server_default="false")

--->有一个搜索表格:

class SearchForm(FlaskForm):
    search_event_by_title = StringField(label="Search event by title", validators=[DataRequired()])
    submit = SubmitField(label="Search", validators=[DataRequired()])

---> 有一个“视图”:

@app.route("/events", methods=["GET", "POST"])
@login_required
def event_list():
    query = db.select(Event.id, Event.title)
    events = db.session.execute(query)
    context = {
        "events": events
    }
    form = SearchForm()
    if form.validate_on_submit():
        search_title = request.form.get('title')
        result = Event.query.filter_by(title=search_title).all()
        return render_template("event/list.html", result=result)
    return render_template("event/list.html", **context, form=form)

“/events”默认显示事件列表(链接),我需要在此页面实现搜索功能,以便在搜索栏过滤数据库查询中输入并呈现正确的输出。我真的不知道如何将查询参数与表单连接起来(如果这里需要的话;我们也可以不使用它)并以正确的方式查询数据库 - 必须按“标题”条件搜索和过滤“事件”。当前代码什么也不做。在“事件”数据库中的现有标题“event/list.html”进行搜索尝试后,该模板不断显示完整的事件列表,忽略过滤。

---> 有html文件(可能主要错误在这里):

{% extends "base.html" %}
{% block content %}
    <h1>Events list</h1>
    <form action="{{ url_for('event_list') }}" method="POST">
    {{ csrf_token }}
    {{ form.search_event_by_title }}
    {{ form.submit }}
    {% for item in result%}
        {{ item.title }}
    {% endfor %}
    <ul>
    {% for item in events %}
        <li><a href="{{url_for('event_detail', id=item.id)}}">{{ item.id }}: {{ item.title }}</a></li>
    {% endfor %}
    </ul>
    </form>
    {% endblock %}

请帮忙。我真的需要弄清楚:(

python sqlite flask flask-sqlalchemy
1个回答
0
投票

如果要使用查询参数,则不需要使用POST方法传输。输入字段的名称和值会自动附加到 URL,并且当您使用 GET 时,可以使用

request.args
在服务器上请求。

我认为 WTForms 对于此目的来说不是最佳的,也不是必需的。

此示例向您展示了在事件中搜索标题的简化版本。

from flask import (
    Flask, 
    render_template, 
    request
)
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import (
    Integer, 
    String, 
    Text
)
from sqlalchemy.orm import (
    DeclarativeBase, 
    Mapped, 
    mapped_column, 
)

app = Flask(__name__)
app.config.from_mapping(
    SQLALCHEMY_DATABASE_URI='sqlite:///sample.db'
)

class Base(DeclarativeBase):
    pass

db = SQLAlchemy(app, model_class=Base)

class Event(db.Model):
    __tablename__ = 'events'
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    title: Mapped[str] = mapped_column(Text, nullable=False)

with app.app_context():
    db.create_all()

    events = [Event(title=f'title-{i}') for i in range(1, 11)]
    db.session.add_all(events)
    db.session.commit()

@app.route('/')
def index():
    qs = request.args.get('qs')
    stmt = db.select(Event)
    if qs:
        stmt = stmt.where(Event.title.ilike(f'%{qs}%'))
    events = db.session.execute(stmt).scalars()
    return render_template('index.html', **locals())
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Index</title>
</head>
<body>
    <form>
        <input type="text" name="qs" />
        <button type="submit">Search</button>
    </form>

    <ul>
        {% for event in events -%}
        <li>{{ event.title }}</li>
        {% endfor -%}
    </ul>
</body>
</html>

您部分使用旧查询接口和关联的方式来定义模型。程序还是一样的。

def index():
    qs = request.args.get('qs')
    query = Event.query
    if qs:
        query = query.filter(Event.title.ilike(f'%{qs}%'))
    events = query.all()
    return render_template('index.html', **locals())
© www.soinside.com 2019 - 2024. All rights reserved.