kuroの覚え書き

96の個人的覚え書き

複数のカラムから検索する

検索フォーム用クラスを一つ追加してみる

class ExomeForm(FlaskForm):
    name = StringField('Search for Username')
    sex = StringField('male or female')
    submit = SubmitField('Search')

いままで検索窓が一つあってボタンを押すとそれを検索ワードとしてMySQLデータベースを検索し、結果を画面に表示させていたわけだが、検索ワードが増えたので

@app.route('/exome/', methods=['GET', 'POST'])
def exome_index():
    form = ExomeForm()
    user = User.query.filter_by(username=form.name.data, sex=form.sex.data)
    return render_template('/exome/index.html', form=form, contents=user, username=form.name.data)

という風にfilter_by()の中身を追加してやると2つのAND検索となる。ただ、このままだとどちらかが空欄だと何も結果が帰ってこないのだ。空欄だとselect *になって欲しいのだが。

またフォームの方で

     sex = SelectField('male or female', choices=[(1, 'male'), (2, 'female')])

とするとプルダウンから選択できるはずなんだけど、なぜか検索結果はゼロになってしまう。
と、おもったら間違っていること判明

     sex = SelectField('male or female', choices=[('male', 'male'), ('female', 'female')])

としておく必要があった('male', 'male')の前側のmaleがpostされるvalueで、後ろのがドロップダウンリストに表示される項目であった。

まだ機能実装していないがラジオボタンでAND/OR/NOTを選択して検索式を立てられるように設計してみた。
レイアウト的なことは今のところ一切考慮せずデフォルトで押し通しているのであまりスマートとはいえないが、やむをえまい。

そろそろ実際のフォーマットのデータでやるかな。


このあと実装すべきもの

  • AND, OR, NOT
  • 前方向一致、部分一致などの一致条件設定
  • 検索結果からの外部データベースへのリンケージ

とりあえず検索ワードが入力されていない項目は検索項目から外す方法としてはifによる条件分岐を使うのが最もかんたんで、速度も早いということなので

@app.route('/exome/', methods=['GET', 'POST'])
def exome_index():
    form = ExomeForm()
    user = User.query
    if form.name.data:
        user = user.filter(User.username==form.name.data)
    if form.sex.data:
        user = user.filter(User.sex==form.sex.data)
#    user = user.filter(User.score<=form.score.data)
    return render_template('/exome/index.html', form=form, contents=user, username=form.name.data, sex=form.sex.data, gene=form.gene.data, score=form.score.data, aon1=form.aon1.data, aon2=form.aon2.data, aon3=form.aon3.data)

このように書くことにした。これに更にAND等の条件を加えていけば良さそうだ。
もう一点わかっていないことが#でコメントアウトしているところで、ある入力した数値以下のものを集める方法がわからない。
filterではだめな様子。

File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/sql/default_comparator.py", line 60, in _boolean_compare
                return BinaryExpression(expr, _const_expr(obj),
                                        operators.isnot,
                                        negate=operators.is_)
            else:
                raise exc.ArgumentError(
                    "Only '=', '!=', 'is_()', 'isnot()', "
                    "'is_distinct_from()', 'isnot_distinct_from()' "
                    "operators can be used with None/True/False")
    else:
        obj = _check_literal(expr, op, obj)
 
sqlalchemy.exc.ArgumentError: Only '=', '!=', 'is_()', 'isnot()', 'is_distinct_from()', 'isnot_distinct_from()' operators can be used with None/True/False

エラーはこんな感じ。数値として見てないから<=はつかえないみたい。
と思っていたのだが、

@app.route('/exome/', methods=['GET', 'POST'])
def exome_index():
    form = ExomeForm()
    user = User.query
    if form.name.data:
        user = user.filter(User.username==form.name.data)
    if form.sex.data:
        user = user.filter(User.sex==form.sex.data)
    if form.score.data:
        user = user.filter(User.score<=form.score.data)
    return render_template('/exome/index.html', form=form, contents=user, username=form.name.data, sex=form.sex.data, gene=form.gene.data, score=form.score.data, aon1=form.aon1.data, aon2=form.aon2.data, aon3=form.aon3.data)

これでちゃんと検索できるようになった。

AND検索だけだけど検索はこれで元のphpバージョンとほぼ近いところまで移植できた感じか。全く知識ゼロから始めて2週間でここまで来た(お盆休みもあったから、10日ほどだね。)