الوحدة 6 — حالة الجلسة والنماذج
الوحدة السابقة عالجت ما يبقى بين المستخدمين (نموذج مُشترَك، اتّصال قاعدة). هذه الوحدة تعالج ما يبقى داخل جلسة المستخدم الواحد: قيمة عدّاد، نتيجة نموذج سابقة، خطوة معالج متعدّد الخطوات. الأداة الوحيدة لذلك هي st.session_state، وهو قاموس يبقى بين إعادات التنفيذ لنفس الجلسة. سنراه من زوايا خمس: القاعدة، الرجعات، النماذج، التنقّل، والسباقات.
القاعدة: قاموس بين إعادات التنفيذ
st.session_state قاموس (بمعنى Python الحرفيّ) خاصّ بكلّ جلسة مستخدم. يمكن الوصول إليه بمفتاح (st.session_state["nom"]) أو بسمة (st.session_state.nom).
import streamlit as st
# تهيئة أوّليّة: مرّة واحدة عند بدء الجلسة.
if "compteur" not in st.session_state:
st.session_state.compteur = 0
st.write(f"العدّاد: {st.session_state.compteur}")
if st.button("زد واحدًا"):
st.session_state.compteur += 1
المستخدم يفتح التطبيق → compteur = 0. يضغط الزرّ → إعادة تنفيذ → compteur = 1. يُغلق التطبيق ثمّ يُعيد الفتح → compteur = 0 مجدّدًا (جلسة جديدة). مستخدم آخر في المتصفّح نفسه (تبويب مختلف) → عدّاده مستقلّ.
قاعدة أوّلى ضروريّة: التهيئة الأوّليّة تكون دائمًا بـif "key" not in st.session_state:، لا بـst.session_state.compteur = 0 مباشرة (وإلّا أعاد الصفر في كلّ إعادة تنفيذ).
المكوّنات وsession_state
كلّ مكوّن له مفتاح (key) يُخزَّن قيمته في session_state تلقائيًّا:
nom = st.text_input("الاسم", key="client_nom")
# بعد كتابة "أحمد"، القيمتان متكافئتان:
assert nom == st.session_state.client_nom == "أحمد"
الفائدة: يمكن قراءة قيمة الحقل من أيّ مكان في الشيفرة بلا الحاجة إلى تمريرها كوسيطة. الفائدة الأخرى: يمكن ضبط القيمة قبل عرض المكوّن:
if "client_nom" not in st.session_state:
st.session_state.client_nom = "غير معروف"
st.text_input("الاسم", key="client_nom")
المكوّن سيعرض «غير معروف» أوّل مرّة. لا تُعطِ value= وkey= معًا لنفس المكوّن؛ ذلك سلوك غامض.
الرجعات (on_change, on_click)
كلّ مكوّن يقبل معلمة on_change (للحقول) أو on_click (للأزرار). دالّة تُنفَّذ قبل إعادة التنفيذ، مع الوصول الكامل إلى session_state.
def basculer_scoring():
st.session_state.derniere_action = "scoring"
st.session_state.compteur_scoring = st.session_state.get("compteur_scoring", 0) + 1
st.button("سجّل", on_click=basculer_scoring)
st.write("آخر فعل:", st.session_state.get("derniere_action"))
st.write("عدد التسجيلات:", st.session_state.get("compteur_scoring", 0))
فرق دقيق: الشيفرة داخل if st.button(...) تُنفَّذ بعد إعادة التنفيذ التي تلت النقر، وقد يكون الترتيب معكوسًا مع مكوّنات أخرى. الشيفرة داخل on_click تُنفَّذ قبل أيّ عرض. لضبط قيم session_state قبل عرض المكوّنات التالية، استعمل الرجعات.
مثال لـon_change:
def normaliser_id():
st.session_state.identifiant = st.session_state.identifiant.strip().upper()
st.text_input("المعرّف", key="identifiant", on_change=normaliser_id)