django: standalone application
Supponiamo di dover creare una piccola applicazione (‘players’)
che inserisca in un database dei dati, ad esempio i nomi
dei calciatori della serie A.
Ci piace utilizzare django per la confidenza che abbiamo con il suo ORM,
ma non abbiamo voglia di sbatterci con tutto il meraviglioso e vastissimo
mondo di django, comprensivo di pattern Model-View-Template, Admin, browser…
Vogliamo invece usare le wx, ma non SQLAlchemy, o peewee.
Non resta che strutturare la nostra mini applicazione in questo modo:
C:\TMP\STANDALONEDJANGOEXAMPLE | main.py | manage.py | settings.py | __init__.py | \---players | controller.py | model.py | models.py | view.py | __init__.py | \---migrations __init__.py
partendo dall’alto, analizziamo i singoli file.
‘main.py’ è il cuore della nostra applicazione django STAND-ALONE e contiene
i settaggi che ci permetteranno di utilizzare solo l’ORM di django:
import os # qui importiamo il modulo settings os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") import sys # qui aggiungiamo il percorso della nostra app al path sys.path.append('/tmp/standalonedjangoexample') # qui aggiungiamo i virtualenv site-packages al sys.path sys.path.append('/tmp/venv/Lib/site-packages') from django.core.wsgi import get_wsgi_application application = get_wsgi_application() if __name__ == '__main__': from players.controller import Controller c = Controller()
questo è il contenuto di ‘manage.py’, necessario per le migrations:
import os import sys sys.dont_write_bytecode = True if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") from django.core.management import execute_from_command_line execute_from_command_line(sys.argv)
poi abbiamo i ‘settings.py’:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'players.db', # Or path to database file if using sqlite3. 'USER': '', # Not used with sqlite3. 'PASSWORD': '', # Not used with sqlite3. 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } } INSTALLED_APPS = ( 'players', ) SECRET_KEY = 'mysecretkey'
Ora entriamo nel cuore della app, che prevede:
– i models che django utilizzerà con il suo ORM
– i file per uno spartano MVC
Questo spartano MVC prevede una file view.py che importa il modulo wx
per creare un’interfaccia di inserimento dati, un model.py per la gestione
dei dati e un controller che metta interagisca con essi tenendoli separati.
Il file models.py (django models)
from django.db import models class Player(models.Model): name = models.CharField(max_length=32) def __unicode__(self): return self.name
il file view.py
import wx class InfoMessage(wx.MessageDialog): """Simple message Dialog""" def __init__(self, parent, message): super(InfoMessage, self).__init__(parent, message, 'info', wx.OK | wx.ICON_EXCLAMATION) if self.ShowModal() == wx.ID_OK: self.Destroy() class ViewNewPlayer(wx.Frame): def __init__(self, parent, controller, title): self.title = title super(ViewNewPlayer, self).__init__(parent=parent, title=title,) #style=STYLE) self.controller = controller self._build() self._bind_widgets() self.Centre() self.Show() def _build(self): self.panel = PanelNewPlayer(parent=self) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.panel, 1, wx.EXPAND) self.SetSizer(sizer) self.SetSize((250, 100)) def _bind_widgets(self): self.Bind(wx.EVT_BUTTON, self.on_quit, self.panel.btn_quit) self.Bind(wx.EVT_BUTTON, self.on_save, self.panel.btn_save) self.Bind(wx.EVT_TEXT, self.on_text_entry, self.panel.name) def show_message(self, message): InfoMessage(parent=self, message=message) def on_text_entry(self, event): entry = self.panel.name.GetValue() if len(entry) > 2: self.panel.btn_save.Enable() else: self.panel.btn_save.Disable() def on_save(self, event): name = self.panel.name.GetValue() self.controller.save_player(name) def on_quit(self, event): self.Destroy() class PanelNewPlayer(wx.Panel): def __init__(self, parent): super(PanelNewPlayer, self).__init__(parent) # Attributes self.name = wx.TextCtrl(self) text_sizer = wx.FlexGridSizer(rows=2, cols=2, hgap=5, vgap=5) text_sizer.Add(wx.StaticText(self, label=''), 0, wx.ALIGN_CENTER_VERTICAL) text_sizer.AddGrowableCol(1) button_sizer = wx.StdDialogButtonSizer() self.btn_save = wx.Button(self, wx.ID_SAVE) self.btn_quit = wx.Button(self, wx.ID_CANCEL) # Buttons initialization self.btn_quit.SetDefault() self.btn_save.Disable() # Sizers button_sizer.AddButton(self.btn_save) button_sizer.AddButton(self.btn_quit) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(text_sizer, 1, wx.EXPAND | wx.ALL, 5) sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 5) button_sizer.Realize() self.SetBackgroundColour('LightGray') self.SetSizer(sizer)
il file model.py (MVC) che si interfaccerà a sua volta con i models di django:
from models import Player class Model(object): @staticmethod def new_player(name): """new_player(name) -> player object""" player = Player.objects.create(name=name.upper()) return player @staticmethod def get_player(name): """get_player(name) -> player object""" return Player.objects.filter(name=name.upper()).first() @staticmethod def get_players(): """get_players() -> iterable""" return Player.objects.all()
il file controller.py
import wx from model import Model from view import ViewNewPlayer class Controller(object): def __init__(self): app = wx.App() self.model = Model() self.view = ViewNewPlayer(parent=None, controller=self, title='New Player') app.MainLoop() def get_player(self, name): return self.model.get_player(name) def save_player(self, name): player_object = self.get_player(name) if player_object: self.view.show_message("Player already exist") else: new_player = self.model.new_player(name) self.view.show_message("New Player %s saved" % new_player.name)
Questo è quanto.
Ovviamente non esistono ancora le tabelle del database e provvediamo con i
comandi:
(venv) C:\tmp\standalonedjangoexample>python manage.py makemigrations Migrations for 'players': players\migrations\0001_initial.py: - Create model Player
e successivamente:
(venv) C:\tmp\standalonedjangoexample>python manage.py migrate Operations to perform: Apply all migrations: players Running migrations: Applying players.0001_initial... OK
poi è possibile eseguire la nostra applicazione utilizzando il file
main.py.
Ovviamente la struttura dell’applicazione può essere fatta in mille modi
diversi, come pure il raggruppamento dei codici.
Lo stesso main.py può fungere da controller riducendo i livelli di
separazione, soprattutto qualora non si volesse utilizzare un
pattern simil-MVC.
Commenti recenti