Передача сеанса SQLAlchemy на контроллер TKinter

В настоящее время я изучаю, как работать с tkinter gui, и я пытаюсь интегрироваться с SQLAlchemy. Первое препятствие заключалось в том, как перемещаться между кадрами без разрушения/закрытия окна, к счастью, я нашел этот вопрос: Переключитесь между двумя кадрами в tkinter. Поэтому я использовал много предоставленного кода и создал простое приложение, которое пытается заставить кого-то войти в систему.

Теперь для части я не могу понять. У меня есть функция _check_credentials (self) глубоко внутри структуры окон, которая пытается запросить db. Я успешно создал таблицу и задал ее в другом месте.

Мне нужно передать сеанс из модуля main.py в класс Login и, наконец, в метод _check_credentials (self).

main.py → Authorzation() → Login() → login_btn = tk.Button() → _check_credentials()

Дополнительная информация:

Я включил весь мой код. Сейчас он запускается, но сбой при нажатии кнопки входа в систему. Я попытался передать сессию напрямую, т.е. Authorzation (Session), но это немедленно сработает.

Кроме того, я стараюсь следовать рекомендациям, изложенным в документах sqlalchemy http://docs.sqlalchemy.org/en/latest/orm/session.html, FAQ: "Когда я создаю сеанс, когда я его совершу, и когда я его закрою? ".

main.py:

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker 

from module1 import Authorzation

import Tkinter as tk

Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()


app = Authorzation()
app.mainloop()

module1.py:

import Tkinter as tk
import user

TITLE_FONT = ("Helvetica", 18, "bold")

class Authorzation(tk.Tk):
 def __init__(self, *args, **kwargs):
 tk.Tk.__init__(self, *args, **kwargs)

 # the container is where we'll stack a bunch of frames
 # on top of each other, then the one we want visible
 # will be raised above the others
 container = tk.Frame(self)
 container.pack(side="top", fill="both", expand=True)
 container.grid_rowconfigure(0, weight=1)
 container.grid_columnconfigure(0, weight=1)

 self.frames = {}
 for F in (Login, Register):
 frame = F(container, self)
 self.frames[F] = frame
 # put all of the pages in the same location; 
 # the one on the top of the stacking order
 # will be the one that is visible.
 frame.grid(row=0, column=0, sticky="nsew")

 self.show_frame(Login)

 def show_frame(self, c):
 '''Show a frame for the given class'''
 frame = self.frames[c]
 frame.tkraise()

class Login(tk.Frame):
 def __init__(self, parent, controller):
 self.controller = controller

 tk.Frame.__init__(self, parent) 
 label = tk.Label(self, text="Title", font=TITLE_FONT)
 label.pack(side="top", fill="x", pady=10)

 #Create the Username field
 label_username = tk.Label(self, text="username")
 label_username.pack()
 self.username = tk.StringVar()
 tk.Entry(self, textvariable=self.username).pack()

 #Create the password field
 label_password = tk.Label(self, text="password")
 label_password.pack()
 self.password = tk.StringVar()
 tk.Entry(self, textvariable=self.password).pack()


 login_btn = tk.Button(self, text="Login", 
 command=self._check_credentials)
 login_btn.pack(pady=5)

 reg_btn = tk.Button(self, text="Registration", 
 command=lambda: controller.show_frame(Register))
 reg_btn.pack(pady=10)

 def _check_credentials(self):
 session_user = session.query(user.User)\
 .filter_by(
 username=self.username
 ).first() 
 if session_user:
 return session_user.check_pwd(), session_user
 else:
 print("Sorry we could not find your username")
 return False, None

 self.controller.show_frame(Login)

class Register(tk.Frame):
 def __init__(self, parent, controller):
 tk.Frame.__init__(self, parent) 
 label = tk.Label(self, text="This is page 1", font=TITLE_FONT)
 label.pack(side="top", fill="x", pady=10)
 button = tk.Button(self, text="Go to the start page", 
 command=lambda: controller.show_frame(Login))
 button.pack()
1 ответ

После исследования на * args и ** kwargs. Я понял, что не пробовал сначала поставить сессию в функции __init__(). Вот как я передал сессию контроллеру.

main.py:

app = Authorzation(session)

module1.py

class Authorzation(tk.Tk):
 def __init__(self, session, *args, **kwargs):
 self.session = session

Когда сессия была в контроллере, было легко ссылаться на нее из фрейма Login().

module1.py:

class Login(tk.Frame):
 def __init__(self, parent, controller):
 self.controller = controller

 ...

 def _check_credentials(self):
 session = self.controller.session

Примечание. Это решение также хорошо, потому что оно облегчает передачу сеанса через кнопку.

licensed under cc by-sa 3.0 with attribution.