Chapter 07

商品詳細ページ

alivelimb
alivelimb
2022.05.25に更新

本章では商品詳細ページを実装していきます。完成イメージは以下の通りです。

商品詳細画面gif

Model, MockDB, Service は商品一覧ページで実装しているので、作成手順は以下の通りです。

No 分類 内容
1 Page PageId を定義し、BasePage を継承したページクラスを作る
2 Application MultiPageApp のpagesにページ ID とページクラスのペアを追加する

Page: PageId を定義し、ページクラスを作る

これまでと同じようにまずは PageId の定義をしていきます。商品詳細ページは一部ログインしないと閲覧できない部分もありますが、ログイン状態に関係なく閲覧できる部分もあるので、PUBLIC_をプレフィックスとしておきましょう。

class PageId(Enum):
    PUBLIC_LOGIN = auto()
    PUBLIC_ITEM_LIST = auto()
    PUBLIC_ITEM_DETAIL = auto() # 追加

ページクラスの追加

商品詳細ページはログインに関係なく閲覧可能な商品詳細部分と、ログインしないと閲覧不可なカートイン部分に分かれます。これらをそれぞれ_render_item_detail_render_cart_inで分割します。

class ItemDetailPage(BasePage):
    def render(self) -> None:
        # タイトルの表示
        st.title(self.title)

        # 商品詳細
        item = self.ssm.get_item() # (B)
        if item is None:
            st.error("商品が選択されていません")
            return # (A)

        self._render_item_detail(item)

        # カートイン
        user = self.ssm.get_user() # (C)
        session_id = self.ssm.get_session_id() # (C)
        if user is None or session_id is None:
            st.warning("カートに追加するためにはログインが必要です。")
            return # (A)

        self._render_cart_in(item, session_id)

コード中(A)で問題なく表示がうまくいかなかった場合、return を返すことで以降のレンダリングを停止します。

コード中(B)では SSM から商品を取得しています。商品一覧ページで詳細ボタンを押下すると、その商品が SSM に保持されるため、詳細ページではその商品を取得できます。

コード中(C)では SSM からユーザ、セッション ID を取得しています。これはログインした時に SSM で保持されています。

商品詳細

商品詳細部分では商品詳細テーブルを表示します。

def _render_item_detail(self, item: Item) -> None:
    show_item = {
        "商品名": item.name,
        "価格": item.price,
        "生産地": item.producing_area,
    }

    # 商品詳細テーブルの表示
    col_size = [1, 2]
    for key, value in show_item.items():
        key_col, value_col = st.columns(col_size)
        key_col.write(key)
        value_col.write(value)

カートイン

カートイン部分では数量を指定して商品をカートに追加します。

def _render_cart_in(self, item: Item, session_id: str) -> None:
    with st.form("item_deteil_form"):
        st.number_input("数量", step=1, min_value=1, max_value=9, key="_quantity") # (A)
        kwargs = dict(item=item, session_id=session_id)
        st.form_submit_button(label="カートに追加", on_click=self._cart_in, kwargs=kwargs) # (B)

def _cart_in(self, item: Item, session_id: str) -> None:
    cart_api_client = self.ssm.get_cart_api_client() # (C)
    cart_item = CartItem(
        item=item,
        quantity=st.session_state["_quantity"],
    )
    cart_api_client.add_item(
        session_id=session_id,
        cart_item=cart_item,
    )
    st.sidebar.success("カートに追加しました")
    st.session_state["_quantity"] = 1

コード中(A)では数量入力ボタンを生成しています。stepを 1 にすることで整数のみ入力を受け付けます。また、数量制限として最小値を 1, 最大値を 9 にしています。

コード中(B)ではコールバック関数を指定していますが、今回は_quantityをコールバック関数内で操作しているためです。_quantityはコード中(A)で定義しており、入力を受け付けるウィジェットの値になるため、コールバック関数を使う必要があります。

コード中(C)の CartAPIClinet やそれ以降の CartItem などはまだ定義していません。これに関しては次の章で紹介します。

Application: ページ ID とページクラスのペアを追加する

最後に作成したページを Application に追加します。

def init_pages(ssm: StreamlitSessionManager) -> list[BasePage]:
    pages = [
        LoginPage(page_id=PageId.PUBLIC_LOGIN, title="ログイン", ssm=ssm),
        ItemListPage(page_id=PageId.PUBLIC_ITEM_LIST, title="商品一覧", ssm=ssm),
        ItemDetailPage(page_id=PageId.PUBLIC_ITEM_DETAIL, title="商品詳細", ssm=ssm), # 追加
    ]
    return pages

SSM, SessionKey 等も登録する必要がありますが、ここでの紹介は省略するため、ソースコードを確認してください。