0
1

More than 3 years have passed since last update.

Anvil の CRUD チュートリアルを改造した時のメモ

Last updated at Posted at 2020-07-23

概要

Anvil は Python でコーディングする、Web ベースの統合開発環境です。
1個のプロジェクトが以下のような構成になっています。

  • Anvil プロジェクト
    • Client Code (UI のデザインとコード)
    • Server Code (サーバサイドのコード)
    • Services (連携するサービス (DB など))

この構成を理解するには、DB の基本操作 (CRUD) を実装するチュートリアル News Aggregator Tutorial を学ぶのが手っ取り早いです。

このチュートリアルのプロジェクトを少し改造して、クイズ集アプリのようにしましたので、その時のメモをご紹介します。

前提

News Aggregator Tutorial をやった前提で説明します (プロジェクトを作るには Anvil へのサインアップが必要です)。
News Aggregator Tutorial ではニュースデータを扱いますが、この構造をそのまま使ってクイズ集アプリとしました。

変更点

リネーム

扱うデータが (構造は同じですが) ニュースからクイズに変わりますので、分かりやすくリネームしました。

  • プロジェクト名
    • 何でも良いですが、'Quiz' としました。
  • フォーム名
    • 'ArticleEdit' から 'QuestionEdit' に変更
    • 'ArticleView' から 'QuestionView' に変更

  • データテーブル名
    • 'articles' から 'questions' に変更
  • カラム名 (および関連するデータバインド)
    • 'title' を 'question' に変更
    • 'content' を 'answer' に変更

  • 他にもフォームのコンポーネントやイベントハンドラ名などを以下のように変更
    • 'articles' → 'questions'
    • 'title' → 'question'
    • 'content' → 'answer'

身も蓋もないことを言うと、あとは入力するデータの内容を「質問」と「答え」にしさえすれば、クイズ集アプリになります。
とはいえ、気になるところもあるので、もう少し改造してみました。

QuestionView

QuestionView フォームに、以下の変更をしました。

「問題」「答え」ラベルを追加

「タイトル」と「記事本文」を「問題」と「答え」として使うので、それぞれ「問題」と「答え」であることを示した方が良いと思い、ラベルを追加しました。

やり方は Toolbox から Label をドラッグ & ドロップするだけです。
Column Panel や Flow Panel を使ってレイアウトの調整もします (なかなか思い通りに行きませんが…)。

答えの表示/非表示を切り替える

クイズなのに答えが丸見えだったので、答えの表示/非表示を切り替えるようにしました。

Toolbox から CheckBox をドラッグ & ドロップし、名前を answer_check としました。
初期状態はチェックがはずれた状態とし、change イベントを追加しました。

イベントハンドラを以下のように書いて、クリックするたびに答えの表示/非表示が切り替わるようにしました。

QuestionView
  def answer_check_change(self, **event_args):
    """This method is called when this checkbox is checked or unchecked"""
    self.answer_label.visible = self.answer_check.checked

答えの方も初期状態を非表示にしました。

カテゴリの初期値

チュートリアルをなぞっただけでは、新規レコード作成時に何もせずに 'SAVE' を押すとエラーになります。
これは、カテゴリが外部参照なのに値が入っていないからです。

None を許容する方法や、フォームを閉じる前にバリデーションする方法が分からなかったので、初期値を与えることで (強引に) 解決しました。
初期値を与えるには、問題を作成するボタンのイベントハンドラ (Homepage フォーム) を以下のようにしました。

変更前

Homepage
  def add_question_button_click(self, **event_args):
    """This method is called when the button is clicked"""
    new_question = {}

    save_clicked = alert(
      ...

変更後

Homepage
  def add_question_button_click(self, **event_args):
    """This method is called when the button is clicked"""
    default_category = anvil.server.call('default_category')  # 追加
    new_question = {'category': default_category}             # 変更

    save_clicked = alert(
      ...

サーバ側のコードにカテゴリの初期値を取得する関数を追加 ('Python' というカテゴリが存在する場合)

ServerModule1
@anvil.server.callable
def default_category():
  return app_tables.categories.get(name='Python')

シャッフルボタン

できれば、問題が1個出て答えると次の問題が出る、というフローにしたいところですが、改造の域を超えそうなので、シャッフルボタンをつけてお茶を濁しました。

仕様としては、以下のようにしました。

  • シャッフルボタンを押すとカードの並びがランダムになる。
    • 同時にシャッフル解除ボタンが有効になる。
  • シャッフル解除ボタンを押すと、DB から取得したままの順になる。
    • 同時にシャッフル解除ボタンが無効になる。
  • 編集をした時などは、DB から取得した順になる。
    • シャッフル解除ボタンは無効になる。

ボタンを追加

シャッフルボタンとシャッフル解除ボタンを追加して、それぞれ shuffle_buttonunshuffle_button としました。

コードの追加・変更

シャッフルボタンのクリックハンドラ

Homepage
  def shuffle_button_click(self, **event_args):
    questions = self.questions_panel.items
    self.questions_panel.items = random.sample(questions, len(questions))
    self.unshuffle_button.enabled = True

シャッフル解除ボタンのクリックハンドラ

Homepage
  def unshuffle_button_click(self, **event_args):
    self.refresh_questions()

refresh_questions() メソッド (元々 refresh_articles() だったもの) も変更

Homepage
  def refresh_questions(self):
    self.questions_panel.items = anvil.server.call('get_questions')
    self.unshuffle_button.enabled = False  # 追加

デモ

以上の変更によりできたクイズ集アプリを、以下の URL で公開しています。
https://Z7NSR2ZWKFYP6CJK.anvil.app/OGKX5IPZ2SLK3TKVBPVJLZGH

所感

まだなかなか、思ったことがすぐ出来る (すぐやり方が見つかる) という感じではないです。
Anvil の UI を思い通りにデザインしようとすると道は険しそうです。

UI を極めるよりは、次は Anvil Uplink という仕組みを試してみたいです。
Anvil Uplink は、ローカルで動いているモデル等を Web アプリから (API サーバみたいな感じに?) 使える仕組みのようです。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1