DZone
Web Dev Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Web Dev Zone > Improving MediaLocker: wxPython, SqlAlchemy, and MVC

Improving MediaLocker: wxPython, SqlAlchemy, and MVC

Mike Driscoll user avatar by
Mike Driscoll
·
Mar. 05, 12 · Web Dev Zone · Interview
Like (0)
Save
Tweet
3.64K Views

Join the DZone community and get the full member experience.

Join For Free

I recently blogged about wxPython, SQLAlchemy, CRUD and MVC. The program that we created in that post was dubbed “MediaLocker”, whether or not it was explicitly stated as such. Anyway, since then, I have received a couple comments about improving the program. One came from Michael Bayer, one of the creative minds behind SQLAlchemy itself and the other comments came from Werner Bruhin, a nice guy who haunts the wxPython mailing list, helping new users. So I went about creating an improved version of the code following their advice. Werner then improved it a bit more. So in this article, we will be looking at improving the code, first with my example and then with his. Enough talk though; let’s get to the meat of story!

Making MediaLocker Better

Michael Bayer and Werner Bruhin both thought that I should only connect to the database once as that’s a fairly “expensive” operation. This could be an issue if there were multiple sessions existing at the same time too, but even in my original code, I made sure to close the session so that wouldn’t happen. When I wrote my original version, I thought about separating out the session creation, but ended up going with what I thought was more straightforward. To fix this niggling issue, I changed the code so that I passed the session object around instead of constantly calling my controller’s connectToDatabase function. You can read more about Sessions here. See the code snippet from mediaLocker.py:

class BookPanel(wx.Panel):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
 
        if not os.path.exists("devdata.db"):
            controller.setupDatabase()
 
        self.session = controller.connectToDatabase()
        try:
            self.bookResults = controller.getAllRecords(self.session)
        except:
            self.bookResults = []


Note that we have a little conditional right up front that will create the database if it doesn’t already exist. Next I create the session object in the main GUI as a property of the panel sub-class. Then I pass it where ever I need to. One example can be seen above where I pass the session object to the controller’s getAllRecords method.

Another big change was to remove the ObjectListView model from model.py and just use the SQLAlchemy table class instead:

########################################################################
class Book(DeclarativeBase):
    """"""
    __tablename__ = "book"
 
    id = Column(Integer, primary_key=True)
    author_id = Column(Integer, ForeignKey("person.id"))
    title = Column(Unicode)
    isbn = Column(Unicode)
    publisher = Column(Unicode)
    person = relation("Person", backref="books", cascade_backrefs=False)
 
    @property
    def author(self):
        return "%s %s" % (self.person.first_name, self.person.last_name)


This is actually mostly the same as the original class except that it uses SQLAlchemy constructs. I also needed to add a special property to return the author’s full name for display in our widget, so we used Python’s built-in function: property which returns a property attribute. It’s easier to understand if you just look at the code. As you can see, we applied property as a decorator to the author method.

Werner’s Additions

Werner’s additions are mostly adding more explicit imports in the model. The biggest change in the model is as follows:

import sys
if not hasattr(sys, 'frozen'):
    # needed when having multiple versions of SA installed
    import pkg_resources
    pkg_resources.require("sqlalchemy") # get latest version
 
import sqlalchemy as sa
import sqlalchemy.orm as sao
import sqlalchemy.ext.declarative as sad
from sqlalchemy.ext.hybrid import hybrid_property
 
maker = sao.sessionmaker(autoflush=True, autocommit=False)
DBSession = sao.scoped_session(maker)
 
class Base(object):
    """Extend the base class
 
    - Provides a nicer representation when a class instance is printed.
        Found on the SA wiki, not included with TG
    """
    def __repr__(self):
        return "%s(%s)" % (
                 (self.__class__.__name__),
                 ', '.join(["%s=%r" % (key, getattr(self, key))
                            for key in sorted(self.__dict__.keys())
                            if not key.startswith('_')]))
 
DeclarativeBase = sad.declarative_base(cls=Base)
metadata = DeclarativeBase.metadata
 
def init_model(engine):
    """Call me before using any of the tables or classes in the model."""
    DBSession.configure(bind=engine)


The first few lines are for people with SetupTools / easy_install on their machine. If the user has multiple versions of SQLALchemy installed, it will force it to use the latest. Most of the other imports are shortened to make it very obvious where various classes and attributes come from. I am honestly not familiar with the hybrid_property, so here’s what its docstring had to say:

A decorator which allows definition of a Python descriptor with both instance-level and class-level behavior.

You can read more here: http://www.sqlalchemy.org/docs/orm/extensions/hybrid.html

Werner also added a little __repr__ method to the Base class to make it return a better representation of the class instance when it’s printed, which is handy for debugging. Finally, he added a function called init_model to initialize the model.

Wrapping Up

Now you should know that Werner and I have decided to make MediaLocker into an example of a wxPython database-enabled application. He’s been doing a bunch of work on it since the simple edits I mentioned above. We’ll be making an official announcement about that soon. In the mean time, I hope that this has helped open your eyes to some fun ways to enhance a project and clean it up a bit. It is my plan to add lots of new features to this program and chronicle those on this blog in addition to all my other articles.

Source Code

  • wxSa2.zip
  • wxSa2.tar


code style

Published at DZone with permission of Mike Driscoll, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Getting Started With RSocket Kotlin
  • Classification of Neural Networks in TensorFlow
  • How To Evaluate Software Quality Assurance Success: KPIs, SLAs, Release Cycles, and Costs
  • Java Microservices: Code Examples, Tutorials, and More

Comments

Web Dev Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo