Você está na página 1de 34

PostgreSQL Conference East 08

POSTMODERN POSTGRESQL APPLICATION DEVELOPMENT

BY DAVID SANKEL @ SANKEL SOFTWARE @ SANKELSOFTWARE.COM

GOALS
Open Source Simple Deployment Platform Independence

Concrete

Abstract

Good Looking Easy to Grasp Fun

Perspectives

FRAMEWORK

THE JOURNEY
make data Design It Glue It Together Put it in a Box

Makefile sql/createDatabase.sql sql/createTables.sql sql/addExampleData.sql

GNU MAKE ROCKS!


DATABASE_NAME=customers PSQL = psql --username postgres --quiet database: $(PSQL) --dbname template1 \ --variable database=$(DATABASE_NAME) \ --file sql/createDatabase.sql $(PSQL) --dbname $(DATABASE_NAME) \ --file sql/createTables.sql $(PSQL) --dbname $(DATABASE_NAME) \ --file sql/addExampleData.sql

SQL/CREATEDATABASE.SQL
DROP DATABASE :database; \set ON_ERROR_STOP CREATE DATABASE :database; \unset ON_ERROR_STOP

SQL/CREATETABLES.SQL
SET client_min_messages TO WARNING; CREATE TABLE customers ( "id" SERIAL PRIMARY KEY, "businessName" text NOT NULL DEFAULT '', "website" text NOT NULL DEFAULT '', "businessAddress" text NOT NULL DEFAULT '', "businessPhone" text NOT NULL DEFAULT '', "contactName" text NOT NULL DEFAULT '', "contactPhone" text NOT NULL DEFAULT '', "notes" text NOT NULL DEFAULT '' );
No fussing!

SQL/ADDEXAMPLEDATA.SQL
INSERT INTO customers ("businessName", "contactName") VALUES ('Sans Enterprises', 'Joe Smith'); INSERT INTO customers ("businessName", "contactName") VALUES ('Watermelon Labs', 'Eric Hendricson'); \set lastId currval(customers_id_seq') \set photo `python util/fileToSqlString.py sql/photo.jpg`

Advanced

THE JOURNEY
make data Design It Glue It Together Put it in a Box

Makefile sql/createDatabase.sql sql/createTables.sql sql/addExampleData.sql

THE JOURNEY
make data Design It Glue It Together Put it in a Box

Qt Designer Forms/CustomerBrowser.ui Forms/CustomerWidget.ui

QT DESIGNER

OUR FORMS

THE JOURNEY
make data Design It Glue It Together Put it in a Box

Qt Designer Forms/CustomerBrowser.ui Forms/CustomerWidget.ui

THE JOURNEY
make data Design It Glue It Together Put it in a Box

Python SQLAlchemy PyQt *.py

PYTHON
def getLinks( html ): """Returns a list of http:// URLS found in the passed html text""" from HTMLParser import HTMLParser class LinkSucker( HTMLParser ): def __init__( self ): HTMLParser.__init__(self) self.links = [] def handle_starttag( self, tag, attrs ): if tag != 'a': return for (name, value) in attrs: if name == "href": self.links.append( value ) try: try linkSucker = LinkSucker() linkSucker.feed( html ) linkSucker.close() return linkSucker.links except: except return []

SQL: THE RIGHT LANGUAGE FOR THE JOB?


Set the customers business name to Billy Bob
No!

UPDATE customers SET businessName = Billy Bob WHERE id = 23 cursor.execute( UPDATE customers SET businessName = %(businessName)s WHERE id = %(id)s , { businessName:Billy Bob, id:23 } ) customer.businessName = Billy Bob

Hell No!

Yes!

SQLALCHEMY
from sqlalchemy import create_engine, MetaData, Table from sqlalchemy.orm import sessionmaker, mapper engine = create_engine( 'postgres://postgres@localhost/customers' ) metadata = MetaData( bind=engine, reflect=True) Session = sessionmaker(bind=engine, autoflush=True, transactional=True) class Customer(object): pass mapper( Customer, Table('customers', metadata ) )

SQLALCHEMY
session = Session() customer = Customer( businessName=Jamb Safety, website=www.jamb.com ) session.save( customer ) for customer in Session.query(Customer).filter( Customer.businessName.like(Jamb%)): print customer.businessName session.commit()

MORE SQLALCHEMY
Complex Object Queries/Relations
session.query(Customer).join('invoices') .filter(Invoice.date=="2008-03-14").all() customer.invoices[0].date invoice.customer.contactPhone

A full expression language


s = select([(customers.c.businessName + ", " + customers.c.website).label('title')], and_( invoices.c.customerId==customers.c.id, invoices.c.date ==2008-03-14 ))

Pooling

PYQT
from PyQt4 import QtCore, QtGui, uic import webbrowser FormClass, BaseClass = uic.loadUiType("forms/CustomerWidget.ui") class CustomerWidget(BaseClass, FormClass): def __init__(self): BaseClass.__init__(self) self.setupUi(self) @QtCore.pyqtSignature("") def on_websitePushButton_clicked( self ): website = str( self.websiteLineEdit.text() ) webbrowser.open( website )

FILL IN THE CUSTOMER WIDGET


class CustomerWidget(BaseClass, FormClass): #... def fromItem( self, customer ): if( if customer.id ): self.idLineEdit.setText( str(customer.id) ) self.businessNameLineEdit.setText( customer.businessName ) self.businessPhoneLineEdit.setText( customer.businessPhone ) #... def toItem( self, customer ): customer.businessName = unicode( self.businessNameLineEdit.text() ) customer.businessPhone = unicode( self.businessPhoneLineEdit.text() ) customer.contactName = unicode( self.contactNameLineEdit.text() ) customer.contactPhone = unicode( self.contactPhoneLineEdit.text() ) #... def clear( self ):

FILL IN THE DATABROWSER


class DataBrowser(BaseClass, FormClass): def __init__(self, Item, ItemWidget): BaseClass.__init__(self) self.setupUi(self) self.Item = Item layout = QtGui.QVBoxLayout() layout.setSpacing(0) self.itemFrame.setLayout(layout) self.itemWidget = ItemWidget() layout.addWidget( self.itemWidget ) self.session = Session() self.items = self.session.query(Item) self.index = 0 self.load() @QtCore.pyqtSignature("") def on_nextPushButton_clicked( self ): if self.index + 1 >= self.items.count(): return self.itemWidget.toItem( self.items[self.index] ) self.index += 1 self.load() SELECT count(customers.id) FROM customers def load(self): self.itemWidget.fromItem( self.items[self.index] ) self.state = self.BROWSE

SOMETHING TO RUN
from PyQt4 import QtGui from DataBrowser import DataBrowser from Customer import Customer from CustomerWidget import CustomerWidget import sys
run: python main.py

def run(): app = QtGui.QApplication(sys.argv) widget = DataBrowser(Customer, CustomerWidget) widget.show() widget.setWindowTitle("Customers 1.0") status = app.exec_() sys.exit(status) if __name__ == "__main__": run()

THE JOURNEY
make data Design It Glue It Together Put it in a Box

Python SQLAlchemy PyQt *.py

FRAMEWORK

THE JOURNEY
make data Design It Glue It Together Put it in a Box

py2exe NSIS

PY2EXE
from distutils.core import setup import py2exe import glob setup( name="Customers", author="Sankel Software", author_email="david@sankelsoftware.com", url="http://sankelsoftware.com", license=GPL", version=1.0.0", windows=[ { "script":"main.py,}], options={"py2exe":{"includes":["sip]}}, data_files=[ ("forms",glob.glob("forms/*.ui")), ] ) release: python setup.py py2exe --quiet --dist-dir=dist

NSIS
Section "Customer Program" SecCustomerProgram SetOutPath $INSTDIR File /r "dist\ ; Write the uninstall keys for Windows WriteRegStr HKLM "Software\Microsoft\..." "DisplayName" "Customers WriteRegStr HKLM "Software\Microsoft\... " "DisplayVersion" "1.0.0 ; Add shortcut to the Desktop CreateShortCut "$DESKTOP\Customers.lnk" "$INSTDIR\main.exe" "" "$INSTDIR\main.exe" 0 SectionEnd Section "Uninstall DeleteRegKey HKLM "Software\Microsoft\... RMDir /r "$INSTDIR\ Delete "$DESKTOP\Customers.lnk SectionEnd

NSIS POSTGRESQL!
Section /o "Customer Database Server" SecServer ; Install PostgreSQL SetOutPath $TEMP File "support\postgresql-8.3-int.msi ReadEnvStr $1 "COMPUTERNAME execwait 'msiexec /i "$TEMP\postgresql-8.3-int.msi" /qr INTERNALLAUNCH=1 CREATESERVICEUSER="1 SERVICEDOMAIN="$1" SERVICEPASSWORD="12345" SUPERPASSWORD="12345 SetOutPath $PROGRAMFILES\PostgreSQL\8.3\data File "server\pg_hba.conf File "server\postgresql.conf ; Reload the configuration files ExecWait '"$PROGRAMFILES\PostgreSQL\8.3\bin\pg_ctl.exe" reload -D "$PROGRAMFILES\PostgreSQL\8.3\data\ ; Set up initial tables and data

MAKE IT
NSIS=NSISDIR="C:\\\NSIS" NSISCONFDIR="C:\\NSIS" "C:\\...\\makensis.exe" release: python setup.py py2exe --quiet --dist-dir=dist $(NSIS) customers.nsi

THE JOURNEY
make data Design It Glue It Together Put it in a Box

BY DAVID SANKEL @ SANKEL SOFTWARE @ SANKELSOFTWARE.COM

PostgreSQL Conference East 08

POSTMODERN POSTGRESQL APPLICATION DEVELOPMENT


Presentation and Source Available at netsuperbrain.com

Você também pode gostar