[Python-es] cómo usar MVC

lopz lowlifebob en gmail.com
Mie Abr 27 04:39:10 CEST 2011


Hola

Siempre he desarrollado pequeños scripts en python, y algo no más de
un main y sus módulos.
Ahora estoy desarrollando un pequeño sistema que consta (a mi parecer)
de 3 sub sistemas
1.- Un módulo para leer el puerto serie y escribir en el
2.- Otro módulo que será el webservice (estoy usando webpy)
3.- Y el otro que es la parte gráfica de la app

Ahora estoy liándome como armar mi estructura para que sea compatible
con MVC (primera ves que uso esto)

Por lo que leí tengo que separar la base de datos de la gui, osea
entre estos 2 no tendrían que hablarse
y para eso está el controlador.

Mi estructura actual es la que pondré a continuación y describiré que
hace cada uno:
.
├── gui (Aquí pongo los widgets que voy creando para usarlo en la GUI,
quizá debería llamar este directorio widgets)
│   ├── __init__.py
│   ├── menu.py
│   ├── notebook.py
│   ├── treeview.py
├── PROGRAMA.py (El programa principal donde el usuario debería hacer click, )
├── media (Aquí tengo imáganes que se usará en la GUI, íconos, de botones, etc)
│   ├── bg
│   ├── icons
│   └── layers
├── modem (Este es el módulo que se encarga que se usará para iniciar,
parar, leer, etc el puerto)
│   ├── __init__.py
│   ├── interface.py (es un módulo que usa el otro de bajo nivel, pero
este corre en un thread aparte para leer constantemente el puerto)
│   └── uspp
           ..... (Aqui el modulo para interactuar con el puserto serie
a bajo nivel, read/write)
├── service (Este es el webservice para lo cual estoy usando webpy)
(Estoy igual trato de seguir MVC y creo que no tengo problemas aquí)
│   ├── __init__.py
│   ├── model.py
│   ├── service.py
│   ├── settings.py
│   ├── static
│   │   ├── index.css
│   │   └── jquery-1.5.1.min.js
│   ├── templates
│   │   ├── index.html
│   │   └── layout.html
│   └── web
│       ├── application.py
          .....(Aqui el resto de modulos de webpy)
├── src (Aquí tengo el src de mi aplicación, y tengo 3 ficheros
llamados model, view y controller)
│   ├── controller.py
│   ├── __init__.py
│   ├── model.py
│   ├── utils.py
│   └── view.py
│
├── var
│   └── datas.db

Ahora tengo en  src.view.py algo como esto:

from gui.treeview import ListStore
from gui.menu import Menu
from gui.notebook import NoteBook


from src.controller import ControlData, ControlService
controldata = ControlData()
controlservice = ControlService()

controllers = (controldata, controlservice)

Y es aquí donde ya empezó el problema, ya que les cuento lo siguiente:

Un ejemplo, necesito desde mi GUI apretar un botón (que está en
menu.py) y que inicie el módulo para leer el puerto (modem.interface)

Yo lo tengo actualmente así:

en mi src.view es donde creo todos los objectos menu.py notebook.py treeview.py
de esta forma:

class Window(object):

    def __init__(self):

        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.connect("delete_event", self.close_application)
        window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
        window.set_default_size(600, 400)
        hbox_container = gtk.HBox(False, 0)
        vbox_container = gtk.VBox(False, 0)

        menu_bar = Menu() <- lo creo ahí y luego lo empaqueto más abajo
        menu_bar.controlservice = controlservice #FIX!!! aquí es donde
tengo el problema, lo describo más abajo
        vbox_container.pack_start(menu_bar, False, False, 0)

Como les he contado en Menu() tengo los botones para iniciar y parar
el modem.service pero este necesita ser creado antes
entonces lo he creado, instanciado en una clase del controller.py que es así:

from model import ModelData

from modem.interface import Modem, Monitor
from modem.testhread import MyThread

class ControlService(object):
    def __init__(self):
        self.modem = Modem(tty='/dev/ttyUSB1')
        self.__callback = None
        self.monitor = None

    def get_modem(self):
        return self.modem

    def get_monitor(self):
        return Monitor(self.modem.waiting, self.__callback)

    def start(self):
        self.monitor = self.get_monitor()
        self.monitor.start()

    def stop(self):
        if self.monitor:
            self.monitor.stop()

    def callback(self, cb):
        self.__callback = cb

class ControlData(object):

    def __init__(self):
        self.model = ModelData()

    def set_title(self):
        self.model.update_title(title)

    def get_title(self):
        datas = self.model.select_title()
        for data in datas:
            return data.value

Entonces este tiene un método para parar y iniciar el modem.service,
pero la forma como se lo paso el objeto creado al Menu()
por medio de un atributo

        menu_bar.controlservice = controlservice

me parece realmente FEA!! y sé que no es lo correcto pero tampoco se
como más podría hacerlo.
y sé que lo mismo me pasará cuando quiera iniciar el webservice desde
la GUI, además los errores que lanzan tanto el webservice como el
modem
tengo que mostrarlos en la GUI,
Otra forma que he pensado es desde controller.py imporar menu.py pero
en este caso no estaría instanciando 2 veces Menu()? desde controller
y desde view.py
la verdad estoy re-perdido en este tema, he pensado por ej crear una
clase base y heredar de controller
y luego un widget que herede de esa clase y luego los demós widgets
que hereden de esa clase, así tendrán los métodos de controller.py
no sé, me gustaría poder ordenar todo para continuar y además aprender
para futuros proyectos :)

Perdón por el mensaje largo pero he intentado ser lo más específico
posible y que no se me quede nada fuera ;)

Saludos!
-- 
lopz es libre, usa --> GNU/linux gentoo

+--[RSA 2048]--+
|  ..o.o=+       |
|   o =o*.+      |
|  . . *oO .      |
|     .EBoo      |
|      o.S         |
+--[lopz.org]--+


Más información sobre la lista de distribución Python-es