SlideShare a Scribd company logo
From SQLAlchemy to Ming with
       TurboGears2




          Alessandro Molina
      alessandro.molina@axant.it
             @__amol__
Simple, Stupid, Serviceable
●   We wanted to offer to development team
    members the opportunity to take a first look at
    MongoDB.
●   We wanted to do this by letting them write an
    actual web app using Python.
●   We wanted a real use case: “expenses and
    incomings” tracking (serviceable)
●   We wanted everyone to understand how it is
    expected to work (stupid)
●   Must be blazing fast to implement, we don't have
    a lot of time (simple)
Involved Technologies

      ●   Python → http://www.python.org
      ●   TurboGears2 → http://www.turbogears.org
      ●   SQLAlchemy → http://www.sqlalchemy.org
      ●   Ming → http://merciless.sourceforge.net/index.html
      ●   Genshi → http://genshi.edgewall.org
      ●   ToscaWidgets → http://toscawidgets.org
      ●   Sprox → http://www.sprox.org
Python Technologies
●   Why? Needed a WebApp ready in 5 minutes while being
    possible to quickly play with the code
●   Python: Our team is manly python developers based
●   TurboGears2: Our team is used to TG. Object Dispatch is really
    comfortable and the framework is incredibly fast to start with
    while still making possible to quickly get under the hood.
●   Genshi: clean and plain xhtml, even designers can understand it,
    also it came by default
●   ToscaWidgets: Can do most of the HTML for us
●   Sprox: Can do most of the CRUD for us
Quickstarting Our Project
                        (tg2dev)Quasar-2:tuts amol$ paster quickstart mt_sqla
●   Project Structure   Enter package name [mt_sqla]: paster quickstart mt_sqla
                         (tg2dev)Quasar-2:tuts amol$
                         Enter package name [mt_sqla]:
                        Would you prefer mako templates? (yes/[no]):
                        Do you need prefer mako templates? (yes/[no]):
                         Would you authentication and authorization in this project? ([yes]/no):

    with Controllers    Selected need implied templates: authorization in this project? ([yes]/no):
                         Do you and authentication and
                         Selected and implied templates:
                          tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template
                           tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template

    for Index Page      (tg2dev)Quasar-2:mt-sqla amol$ python setup.py develop
                         (tg2dev)Quasar-2:mt-sqla amol$ python setup.py develop
                        paster srunning develop
                         paster srunning develop
                        Installed /Users/amol/wrk/tuts/mt-sqla
                         Installed /Users/amol/wrk/tuts/mt-sqla

●   Models for Users,   (tg2dev)Quasar-2:mt-sqla amol$ paster setup-app development.ini
                         (tg2dev)Quasar-2:mt-sqla amol$ paster setup-app development.ini
                        Running setup_config() from mt_sqla.websetup
                         Running setup_config() from mt_sqla.websetup
                            Creating tables

    Groups and
                             Creating tables
                        (tg2dev)Quasar-2:mt-sqla amol$ paster serve development.ini
                         (tg2dev)Quasar-2:mt-sqla amol$ paster serve development.ini
                        Starting server in PID 23939.

    Permission
                        serving on server in PID 23939.
                         Starting http://127.0.0.1:8080
                         serving on http://127.0.0.1:8080




●   Authentication      (tg2dev)Quasar-2:tuts amol$ paster quickstart –ming mt_ming
                        Enter package name [mt_ming]: paster quickstart –ming mt_ming
                         (tg2dev)Quasar-2:tuts amol$
                         Enter package name [mt_ming]:

    and Authorization
                        Would you prefer mako templates? (yes/[no]):
                        Do you need prefer mako templates? (yes/[no]):
                         Would you authentication and authorization in this project? ([yes]/no):
                        Selected need implied templates: authorization in this project? ([yes]/no):
                         Do you and authentication and
                         Selected and implied templates:
                          tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template
                           tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template

●   Both on SQLA        (tg2dev)Quasar-2:mt-ming amol$ python setup.py develop
                         (tg2dev)Quasar-2:mt-ming amol$ python setup.py develop
                        paster srunning develop
                         paster srunning develop
                        Installed /Users/amol/wrk/tuts/mt-ming

    and Ming
                         Installed /Users/amol/wrk/tuts/mt-ming
                        (tg2dev)Quasar-2:mt-ming amol$ paster setup-app development.ini
                         (tg2dev)Quasar-2:mt-ming amol$ paster setup-app development.ini
                        Running setup_app() from mt_ming.websetup
                         Running setup_app() from mt_ming.websetup
                        (tg2dev)Quasar-2:mt-ming amol$ paster serve development.ini
                         (tg2dev)Quasar-2:mt-ming amol$ paster serve development.ini
                        Starting server in PID 23939.
                        serving on server in PID 23939.
                         Starting http://127.0.0.1:8080
                         serving on http://127.0.0.1:8080
Overview

               Browser                      Genshi




                                         ToscaWidgets
              TurboGears




             Controller Code            Sprox (TGAdmin)




      Ming                 SQLAlchemy
SQLAlchemy
●   Supports pratically everything: PostgresSQL,
    MySQL, SQLite, Firebird, Oracle, MSSQL, Sybase,
    DB2, Informix, SAPDB, MSAccess
●   Declarative ORM layer with access to a powerful and
    flexible query builder
●   Unlike many tools, it never enforces schemas or
    relies on naming conventions of any kind.
●   Unit Of Work system organizes pending
    insert/update/delete operations into queues and
    flushes them all in one batch (Patterns of Enterprise
    Application Architecture - Martin Fowler)
Python MongoDB Ecosystem
  ●   PyMongo: Driver for MongoDB, everything is a dictionary
  ●   MongoEngine: ORM, query language is familiar to Django users
  ●   Ming: ORM, query language is familiar to SQLAlchemy users
  ●   MongoKit: ORM, written to be as simple and light as possible

MongoKit                                              Ming
class BlogPost(Document):                             class WikiComment(MappedClass):
    structure = {                                         class __mongometa__:
        'title':unicode,                                      session = session
        'body':unicode,                                       name = 'wiki_comment'
        'author':unicode,
        'date_creation':datetime.datetime,                _id = FieldProperty(schema.ObjectId)
        'rank':int                                        text=FieldProperty(str, if_missing='')
    }                                                     page_id = ForeignIdProperty('WikiPage')
                                                          page=RelationProperty('WikiPage')
tutorial.BlogPost.find({'body': {'$exists': True}})
                                                      WikiComment.query.find({'text':{'$exists':True}})


MongoEngine                                           PyMongo
class User(Document):                                 post = {"author": "Mike",
    email = StringField(required=True)                ...     "text": "My first blog post!",
    first_name = StringField(max_length=50)           ...     "tags": ["mongodb", "python"],
    last_name = StringField(max_length=50)            ...     "date": datetime.datetime.utcnow()}

Users.objects(age__lte=18)                            db.posts.find({"author": "Mike"})
Ming
●   SQLAlchemy inspired, easy to catch up if you are
    used to SQLAlchemy
●   Declarative ORM layer, use ORM through objects
    and get direct access to mongo through collections
●   Integrated Migrations (deprecated attributes and
    even on-demand lazy migration code)
●   Unit of Work, we tried it, we loved it, we wanted it
    even on MongoDB
●   Mongo In Memory, complete implementation of
    MongoDB in memory for unit testing
Some Little Magic (TGAdmin)




●   It did CRUD for us.
●   Works both with SQLAlchemy and Ming
●   Comes for free with TurboGears2
●   Sprox based, deeply customizable
Storing our Data
from sqlalchemy import Table, Column                  from ming import schema as s
 from sqlalchemy import Table, Column
from sqlalchemy.types import Unicode, Integer,         from ming import schema as s
                                                      from ming.orm import FieldProperty, Mapper
Float, sqlalchemy.types import Unicode, Integer,
 from DateTime                                         from ming.orm import FieldProperty, Mapper
                                                      from ming.orm.declarative import MappedClass
 Float, DateTime
from datetime import datetime                          from ming.orm.declarative import MappedClass
                                                      from session import DBSession
 from datetime import datetime                         from session import DBSession
                                                      from datetime import datetime
                                                       from datetime import datetime
class MoneyTransfer(DeclarativeBase):                 class MoneyTransfer(MappedClass):
 class MoneyTransfer(DeclarativeBase):
    __tablename__ = 'money_transfers'                  class MoneyTransfer(MappedClass):
                                                          class __mongometa__:
     __tablename__ = 'money_transfers'                     class __mongometa__:
                                                              session = DBSession
                                                               session = DBSession
                                                              name = 'money_transfers'
                                                               name = 'money_transfers'
    uid = Column(Integer, autoincrement=True,            _id = FieldProperty(s.ObjectId)
     uid = Column(Integer,primary_key=True)
                            autoincrement=True,           _id = FieldProperty(s.ObjectId)
                                                         date = FieldProperty(s.DateTime,
                            primary_key=True)
    date = Column(DateTime, default=datetime.now)         date = FieldProperty(s.DateTime,
                                                                              if_missing=datetime.now)
    sign = =Column(Integer, default=1)
     date    Column(DateTime, default=datetime.now)                            if_missing=datetime.now)
                                                         sign = FieldProperty(s.Int, if_missing=1)
     sign = Column(Integer, default=1)
    description = Column(Unicode(255))                    sign = FieldProperty(s.Int, if_missing=1)
                                                         description = FieldProperty(s.String)
     description = Column(Unicode(255))
    value = Column(Float, default=0)                      description = FieldProperty(s.String)
                                                         value = FieldProperty(s.Float, if_missing=0)
     value = Column(Float, default=0)                     value = FieldProperty(s.Float, if_missing=0)
Retrieving and Displaying Data
from tw.forms import DataGrid                                  from tw.forms import DataGrid
from tw.forms.datagrid DataGrid
 from tw.forms import import Column                            from tw.forms.datagrid DataGrid
                                                                from tw.forms import import Column
 from tw.forms.datagrid import Column                           from tw.forms.datagrid import Column
transactions_grid = DataGrid(fields=[                          transactions_grid = DataGrid(fields=[
 transactions_grid 'date'),
    Column('Date', = DataGrid(fields=[                          transactions_grid 'date'),
                                                                   Column('Date', = DataGrid(fields=[
     Column('Date', 'date'),
    Column('Description', 'description'),                           Column('Date', 'date'),
                                                                   Column('Description', 'description'),
     Column('Description', 'description'),
    Column('Value', lambda row:row.value*row.sign)])                Column('Description', 'description'),
                                                                   Column('Value', lambda row:row.value*row.sign)])
     Column('Value', lambda row:row.value*row.sign)])               Column('Value', lambda row:row.value*row.sign)])
class RootController(BaseController):                          class RootController(BaseController):
 class RootController(BaseController):
    @expose('mt_sqla.templates.index')                          class RootController(BaseController):
                                                                   @expose('mt_ming.templates.index')
     @expose('mt_sqla.templates.index')
    def index(self):                                                @expose('mt_ming.templates.index')
                                                                   def index(self):
     def index(self): DBSession.query(MoneyTransfer).all()
        transactions =                                              def index(self): MoneyTransfer.query.find().all()
                                                                       transactions =
         transactions = DBSession.query(MoneyTransfer).all()
        total = sum((t.value*t.sign for t in transactions))             transactions = MoneyTransfer.query.find().all()
                                                                       total = sum((t.value*t.sign for t in transactions))
         total = sum((t.value*t.sign for t in transactions))
        return dict(page='index',                                       total = sum((t.value*t.sign for t in transactions))
                                                                       return dict(page='index',
         return dict(page='index',
                     transactions=transactions,                         return dict(page='index',
                                                                                    transactions=transactions,
                      transactions=transactions,
                     transactions_grid=transactions_grid,                            transactions=transactions,
                                                                                    transactions_grid=transactions_grid,
                      transactions_grid=transactions_grid,
                     total=total)                                                    transactions_grid=transactions_grid,
                                                                                    total=total)
                      total=total)                                                   total=total)




         <div style="width:650px; margin-top:20px;">
          <div style="width:650px; margin-top:20px;">
             <a href="${tg.url('/admin/moneytransfers/new')}">Add New Transaction</a>
              <a href="${tg.url('/admin/moneytransfers/new')}">Add New Transaction</a>
             ${transactions_grid(transactions)}
              ${transactions_grid(transactions)}
             <div style="text-align:right;"><strong>AVAILABLE:</strong> ${total}</div>
              <div style="text-align:right;"><strong>AVAILABLE:</strong> ${total}</div>
         </div>
          </div>
What changed
●   Template remained the same. Thanks god we
    have an ORM.
●   Had to change the model.
●   Had to change just 1 line of controller code to
    retrieve the data. Ming and SQLA are similar
    enough
●   Did we really need to change that line? We just
    want to get a list of objects...
Sprox, abstraction over abstraction
   ●   ORMProvider, provides an abstraction over the ORM
   ●   ORMProviderSelector, automatically detects the provider to
       use from a model.
   ●   Mix those together and you have a db independent layer.
        ●   Provider.query(self, entity, limit=None, offset=0, limit_fields=None,
            order_by=None, desc=False) → get all objects of a collection
        ●   Provider.get_obj(self, entity, params) → get an object
        ●   Provider.update(self, entity, params) → update an object
        ●   Provider.create(self, entity, params) → create a new object
SQLAlchemy
transactions = DBSession.query(MoneyTransfer).all()
 transactions = DBSession.query(MoneyTransfer).all()
                                                       Sprox
                                                       count, transactions = provider.query(MoneyTransfer)
Ming                                                    count, transactions = provider.query(MoneyTransfer)

transactions = MoneyTransfer.query.find().all()
 transactions = MoneyTransfer.query.find().all()
Experiments Experience

●   Starting with a really simple use case made people
    get comfortable with MongoDB and feel confident
    enough to start learning more complex features.
●   The idea of being possible to use sprox to abstract
    over the db, making possible to switch back anytime,
    created a “safety net” idea in people.
●   When people feel safe they start experimenting a lot
    more and learn by themselves.

More Related Content

PPT
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
PDF
PyconIE 2016 - Kajiki, the fast and validated template engine your were looki...
PDF
Reactive & Realtime Web Applications with TurboGears2
PPTX
Node.js/io.js Native C++ Addons
PDF
Writing native bindings to node.js in C++
PPTX
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
KEY
Beautiful Documentation with YUI Doc
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
PyconIE 2016 - Kajiki, the fast and validated template engine your were looki...
Reactive & Realtime Web Applications with TurboGears2
Node.js/io.js Native C++ Addons
Writing native bindings to node.js in C++
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Beautiful Documentation with YUI Doc

What's hot (20)

PDF
Es.next
KEY
Node.js - Best practices
PDF
FalsyValues. Dmitry Soshnikov - ECMAScript 6
ODP
Supercharging reflective libraries with InvokeDynamic
PPTX
Vue.js + Django - configuración para desarrollo con webpack y HMR
KEY
Python在豆瓣的应用
PDF
FwDays 2021: Metarhia Technology Stack for Node.js
PDF
JavaScript 101
PPTX
The State of JavaScript
PDF
Powerful JavaScript Tips and Best Practices
PDF
Fun Teaching MongoDB New Tricks
PDF
Unleash your inner console cowboy
ODP
This upload requires better support for ODP format
PPTX
Building High Performance Web Applications and Sites
PPTX
Dgeni documentation generator
PPTX
Introduction to Grails Framework
PPTX
All you need to know about the JavaScript event loop
PDF
Reactive, component 그리고 angular2
PPT
Svcc Building Rich Applications with Groovy's SwingBuilder
Es.next
Node.js - Best practices
FalsyValues. Dmitry Soshnikov - ECMAScript 6
Supercharging reflective libraries with InvokeDynamic
Vue.js + Django - configuración para desarrollo con webpack y HMR
Python在豆瓣的应用
FwDays 2021: Metarhia Technology Stack for Node.js
JavaScript 101
The State of JavaScript
Powerful JavaScript Tips and Best Practices
Fun Teaching MongoDB New Tricks
Unleash your inner console cowboy
This upload requires better support for ODP format
Building High Performance Web Applications and Sites
Dgeni documentation generator
Introduction to Grails Framework
All you need to know about the JavaScript event loop
Reactive, component 그리고 angular2
Svcc Building Rich Applications with Groovy's SwingBuilder
Ad

Similar to From SQLAlchemy to Ming with TurboGears2 (20)

PDF
Database madness with_mongoengine_and_sql_alchemy
PDF
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
PDF
Extensions on PostgreSQL
PDF
Using Ruby on Rails with legacy Oracle databases
KEY
MongoDB at ZPUGDC
PDF
Bar Camp Auckland - Mongo DB Presentation BCA4
PDF
EuroPython 2013 - Python3 TurboGears Training
PDF
Cutting Edge Data Processing with PHP & XQuery
PDF
TurboGears2 Pluggable Applications
PDF
Going beyond Django ORM limitations with Postgres
PPTX
PhillyDB Talk - Beyond Batch
PDF
Postgres database Ibrahem Batta
KEY
MongoDB hearts Django? (Django NYC)
PDF
Heroku Postgres Cloud Database Webinar
PDF
An Open Source NoSQL solution for Internet Access Logs Analysis
PPTX
Googleappengineintro 110410190620-phpapp01
PPT
Rapid, Scalable Web Development with MongoDB, Ming, and Python
PDF
Django - 次の一歩 gumiStudy#3
PDF
gumiStudy#3 Django – 次の一歩
PDF
Pyconie 2012
Database madness with_mongoengine_and_sql_alchemy
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
Extensions on PostgreSQL
Using Ruby on Rails with legacy Oracle databases
MongoDB at ZPUGDC
Bar Camp Auckland - Mongo DB Presentation BCA4
EuroPython 2013 - Python3 TurboGears Training
Cutting Edge Data Processing with PHP & XQuery
TurboGears2 Pluggable Applications
Going beyond Django ORM limitations with Postgres
PhillyDB Talk - Beyond Batch
Postgres database Ibrahem Batta
MongoDB hearts Django? (Django NYC)
Heroku Postgres Cloud Database Webinar
An Open Source NoSQL solution for Internet Access Logs Analysis
Googleappengineintro 110410190620-phpapp01
Rapid, Scalable Web Development with MongoDB, Ming, and Python
Django - 次の一歩 gumiStudy#3
gumiStudy#3 Django – 次の一歩
Pyconie 2012
Ad

More from Alessandro Molina (12)

PDF
PyCon Ireland 2022 - PyArrow full stack.pdf
PDF
EP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
PDF
EuroPython 2015 - Storing files for the web is not as straightforward as you ...
PDF
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
PDF
PyConIT6 - Messing up with pymongo for fun and profit
PDF
PyConFR 2014 - DEPOT, Story of a file.write() gone wrong
PDF
PyConUK 2014 - PostMortem Debugging and Web Development Updated
PDF
Post-Mortem Debugging and Web Development
PDF
MongoTorino 2013 - BSON Mad Science for fun and profit
PDF
PyConUK2013 - Validated documents on MongoDB with Ming
PDF
PyGrunn2013 High Performance Web Applications with TurboGears
PDF
Rapid Prototyping with TurboGears2
PyCon Ireland 2022 - PyArrow full stack.pdf
EP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
EuroPython 2015 - Storing files for the web is not as straightforward as you ...
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
PyConIT6 - Messing up with pymongo for fun and profit
PyConFR 2014 - DEPOT, Story of a file.write() gone wrong
PyConUK 2014 - PostMortem Debugging and Web Development Updated
Post-Mortem Debugging and Web Development
MongoTorino 2013 - BSON Mad Science for fun and profit
PyConUK2013 - Validated documents on MongoDB with Ming
PyGrunn2013 High Performance Web Applications with TurboGears
Rapid Prototyping with TurboGears2

Recently uploaded (20)

PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
Cloud computing and distributed systems.
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Empathic Computing: Creating Shared Understanding
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PPTX
A Presentation on Artificial Intelligence
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Approach and Philosophy of On baking technology
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
Big Data Technologies - Introduction.pptx
PDF
Encapsulation theory and applications.pdf
PDF
A comparative analysis of optical character recognition models for extracting...
Advanced methodologies resolving dimensionality complications for autism neur...
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
20250228 LYD VKU AI Blended-Learning.pptx
Cloud computing and distributed systems.
The AUB Centre for AI in Media Proposal.docx
Empathic Computing: Creating Shared Understanding
Network Security Unit 5.pdf for BCA BBA.
gpt5_lecture_notes_comprehensive_20250812015547.pdf
A Presentation on Artificial Intelligence
sap open course for s4hana steps from ECC to s4
Dropbox Q2 2025 Financial Results & Investor Presentation
Building Integrated photovoltaic BIPV_UPV.pdf
Unlocking AI with Model Context Protocol (MCP)
Diabetes mellitus diagnosis method based random forest with bat algorithm
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Approach and Philosophy of On baking technology
Per capita expenditure prediction using model stacking based on satellite ima...
Big Data Technologies - Introduction.pptx
Encapsulation theory and applications.pdf
A comparative analysis of optical character recognition models for extracting...

From SQLAlchemy to Ming with TurboGears2

  • 1. From SQLAlchemy to Ming with TurboGears2 Alessandro Molina alessandro.molina@axant.it @__amol__
  • 2. Simple, Stupid, Serviceable ● We wanted to offer to development team members the opportunity to take a first look at MongoDB. ● We wanted to do this by letting them write an actual web app using Python. ● We wanted a real use case: “expenses and incomings” tracking (serviceable) ● We wanted everyone to understand how it is expected to work (stupid) ● Must be blazing fast to implement, we don't have a lot of time (simple)
  • 3. Involved Technologies ● Python → http://www.python.org ● TurboGears2 → http://www.turbogears.org ● SQLAlchemy → http://www.sqlalchemy.org ● Ming → http://merciless.sourceforge.net/index.html ● Genshi → http://genshi.edgewall.org ● ToscaWidgets → http://toscawidgets.org ● Sprox → http://www.sprox.org
  • 4. Python Technologies ● Why? Needed a WebApp ready in 5 minutes while being possible to quickly play with the code ● Python: Our team is manly python developers based ● TurboGears2: Our team is used to TG. Object Dispatch is really comfortable and the framework is incredibly fast to start with while still making possible to quickly get under the hood. ● Genshi: clean and plain xhtml, even designers can understand it, also it came by default ● ToscaWidgets: Can do most of the HTML for us ● Sprox: Can do most of the CRUD for us
  • 5. Quickstarting Our Project (tg2dev)Quasar-2:tuts amol$ paster quickstart mt_sqla ● Project Structure Enter package name [mt_sqla]: paster quickstart mt_sqla (tg2dev)Quasar-2:tuts amol$ Enter package name [mt_sqla]: Would you prefer mako templates? (yes/[no]): Do you need prefer mako templates? (yes/[no]): Would you authentication and authorization in this project? ([yes]/no): with Controllers Selected need implied templates: authorization in this project? ([yes]/no): Do you and authentication and Selected and implied templates: tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template for Index Page (tg2dev)Quasar-2:mt-sqla amol$ python setup.py develop (tg2dev)Quasar-2:mt-sqla amol$ python setup.py develop paster srunning develop paster srunning develop Installed /Users/amol/wrk/tuts/mt-sqla Installed /Users/amol/wrk/tuts/mt-sqla ● Models for Users, (tg2dev)Quasar-2:mt-sqla amol$ paster setup-app development.ini (tg2dev)Quasar-2:mt-sqla amol$ paster setup-app development.ini Running setup_config() from mt_sqla.websetup Running setup_config() from mt_sqla.websetup Creating tables Groups and Creating tables (tg2dev)Quasar-2:mt-sqla amol$ paster serve development.ini (tg2dev)Quasar-2:mt-sqla amol$ paster serve development.ini Starting server in PID 23939. Permission serving on server in PID 23939. Starting http://127.0.0.1:8080 serving on http://127.0.0.1:8080 ● Authentication (tg2dev)Quasar-2:tuts amol$ paster quickstart –ming mt_ming Enter package name [mt_ming]: paster quickstart –ming mt_ming (tg2dev)Quasar-2:tuts amol$ Enter package name [mt_ming]: and Authorization Would you prefer mako templates? (yes/[no]): Do you need prefer mako templates? (yes/[no]): Would you authentication and authorization in this project? ([yes]/no): Selected need implied templates: authorization in this project? ([yes]/no): Do you and authentication and Selected and implied templates: tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template tg.devtools#turbogears2 TurboGears 2. Standard Quickstart Template ● Both on SQLA (tg2dev)Quasar-2:mt-ming amol$ python setup.py develop (tg2dev)Quasar-2:mt-ming amol$ python setup.py develop paster srunning develop paster srunning develop Installed /Users/amol/wrk/tuts/mt-ming and Ming Installed /Users/amol/wrk/tuts/mt-ming (tg2dev)Quasar-2:mt-ming amol$ paster setup-app development.ini (tg2dev)Quasar-2:mt-ming amol$ paster setup-app development.ini Running setup_app() from mt_ming.websetup Running setup_app() from mt_ming.websetup (tg2dev)Quasar-2:mt-ming amol$ paster serve development.ini (tg2dev)Quasar-2:mt-ming amol$ paster serve development.ini Starting server in PID 23939. serving on server in PID 23939. Starting http://127.0.0.1:8080 serving on http://127.0.0.1:8080
  • 6. Overview Browser Genshi ToscaWidgets TurboGears Controller Code Sprox (TGAdmin) Ming SQLAlchemy
  • 7. SQLAlchemy ● Supports pratically everything: PostgresSQL, MySQL, SQLite, Firebird, Oracle, MSSQL, Sybase, DB2, Informix, SAPDB, MSAccess ● Declarative ORM layer with access to a powerful and flexible query builder ● Unlike many tools, it never enforces schemas or relies on naming conventions of any kind. ● Unit Of Work system organizes pending insert/update/delete operations into queues and flushes them all in one batch (Patterns of Enterprise Application Architecture - Martin Fowler)
  • 8. Python MongoDB Ecosystem ● PyMongo: Driver for MongoDB, everything is a dictionary ● MongoEngine: ORM, query language is familiar to Django users ● Ming: ORM, query language is familiar to SQLAlchemy users ● MongoKit: ORM, written to be as simple and light as possible MongoKit Ming class BlogPost(Document): class WikiComment(MappedClass): structure = { class __mongometa__: 'title':unicode, session = session 'body':unicode, name = 'wiki_comment' 'author':unicode, 'date_creation':datetime.datetime, _id = FieldProperty(schema.ObjectId) 'rank':int text=FieldProperty(str, if_missing='') } page_id = ForeignIdProperty('WikiPage') page=RelationProperty('WikiPage') tutorial.BlogPost.find({'body': {'$exists': True}}) WikiComment.query.find({'text':{'$exists':True}}) MongoEngine PyMongo class User(Document): post = {"author": "Mike", email = StringField(required=True) ... "text": "My first blog post!", first_name = StringField(max_length=50) ... "tags": ["mongodb", "python"], last_name = StringField(max_length=50) ... "date": datetime.datetime.utcnow()} Users.objects(age__lte=18) db.posts.find({"author": "Mike"})
  • 9. Ming ● SQLAlchemy inspired, easy to catch up if you are used to SQLAlchemy ● Declarative ORM layer, use ORM through objects and get direct access to mongo through collections ● Integrated Migrations (deprecated attributes and even on-demand lazy migration code) ● Unit of Work, we tried it, we loved it, we wanted it even on MongoDB ● Mongo In Memory, complete implementation of MongoDB in memory for unit testing
  • 10. Some Little Magic (TGAdmin) ● It did CRUD for us. ● Works both with SQLAlchemy and Ming ● Comes for free with TurboGears2 ● Sprox based, deeply customizable
  • 11. Storing our Data from sqlalchemy import Table, Column from ming import schema as s from sqlalchemy import Table, Column from sqlalchemy.types import Unicode, Integer, from ming import schema as s from ming.orm import FieldProperty, Mapper Float, sqlalchemy.types import Unicode, Integer, from DateTime from ming.orm import FieldProperty, Mapper from ming.orm.declarative import MappedClass Float, DateTime from datetime import datetime from ming.orm.declarative import MappedClass from session import DBSession from datetime import datetime from session import DBSession from datetime import datetime from datetime import datetime class MoneyTransfer(DeclarativeBase): class MoneyTransfer(MappedClass): class MoneyTransfer(DeclarativeBase): __tablename__ = 'money_transfers' class MoneyTransfer(MappedClass): class __mongometa__: __tablename__ = 'money_transfers' class __mongometa__: session = DBSession session = DBSession name = 'money_transfers' name = 'money_transfers' uid = Column(Integer, autoincrement=True, _id = FieldProperty(s.ObjectId) uid = Column(Integer,primary_key=True) autoincrement=True, _id = FieldProperty(s.ObjectId) date = FieldProperty(s.DateTime, primary_key=True) date = Column(DateTime, default=datetime.now) date = FieldProperty(s.DateTime, if_missing=datetime.now) sign = =Column(Integer, default=1) date Column(DateTime, default=datetime.now) if_missing=datetime.now) sign = FieldProperty(s.Int, if_missing=1) sign = Column(Integer, default=1) description = Column(Unicode(255)) sign = FieldProperty(s.Int, if_missing=1) description = FieldProperty(s.String) description = Column(Unicode(255)) value = Column(Float, default=0) description = FieldProperty(s.String) value = FieldProperty(s.Float, if_missing=0) value = Column(Float, default=0) value = FieldProperty(s.Float, if_missing=0)
  • 12. Retrieving and Displaying Data from tw.forms import DataGrid from tw.forms import DataGrid from tw.forms.datagrid DataGrid from tw.forms import import Column from tw.forms.datagrid DataGrid from tw.forms import import Column from tw.forms.datagrid import Column from tw.forms.datagrid import Column transactions_grid = DataGrid(fields=[ transactions_grid = DataGrid(fields=[ transactions_grid 'date'), Column('Date', = DataGrid(fields=[ transactions_grid 'date'), Column('Date', = DataGrid(fields=[ Column('Date', 'date'), Column('Description', 'description'), Column('Date', 'date'), Column('Description', 'description'), Column('Description', 'description'), Column('Value', lambda row:row.value*row.sign)]) Column('Description', 'description'), Column('Value', lambda row:row.value*row.sign)]) Column('Value', lambda row:row.value*row.sign)]) Column('Value', lambda row:row.value*row.sign)]) class RootController(BaseController): class RootController(BaseController): class RootController(BaseController): @expose('mt_sqla.templates.index') class RootController(BaseController): @expose('mt_ming.templates.index') @expose('mt_sqla.templates.index') def index(self): @expose('mt_ming.templates.index') def index(self): def index(self): DBSession.query(MoneyTransfer).all() transactions = def index(self): MoneyTransfer.query.find().all() transactions = transactions = DBSession.query(MoneyTransfer).all() total = sum((t.value*t.sign for t in transactions)) transactions = MoneyTransfer.query.find().all() total = sum((t.value*t.sign for t in transactions)) total = sum((t.value*t.sign for t in transactions)) return dict(page='index', total = sum((t.value*t.sign for t in transactions)) return dict(page='index', return dict(page='index', transactions=transactions, return dict(page='index', transactions=transactions, transactions=transactions, transactions_grid=transactions_grid, transactions=transactions, transactions_grid=transactions_grid, transactions_grid=transactions_grid, total=total) transactions_grid=transactions_grid, total=total) total=total) total=total) <div style="width:650px; margin-top:20px;"> <div style="width:650px; margin-top:20px;"> <a href="${tg.url('/admin/moneytransfers/new')}">Add New Transaction</a> <a href="${tg.url('/admin/moneytransfers/new')}">Add New Transaction</a> ${transactions_grid(transactions)} ${transactions_grid(transactions)} <div style="text-align:right;"><strong>AVAILABLE:</strong> ${total}</div> <div style="text-align:right;"><strong>AVAILABLE:</strong> ${total}</div> </div> </div>
  • 13. What changed ● Template remained the same. Thanks god we have an ORM. ● Had to change the model. ● Had to change just 1 line of controller code to retrieve the data. Ming and SQLA are similar enough ● Did we really need to change that line? We just want to get a list of objects...
  • 14. Sprox, abstraction over abstraction ● ORMProvider, provides an abstraction over the ORM ● ORMProviderSelector, automatically detects the provider to use from a model. ● Mix those together and you have a db independent layer. ● Provider.query(self, entity, limit=None, offset=0, limit_fields=None, order_by=None, desc=False) → get all objects of a collection ● Provider.get_obj(self, entity, params) → get an object ● Provider.update(self, entity, params) → update an object ● Provider.create(self, entity, params) → create a new object SQLAlchemy transactions = DBSession.query(MoneyTransfer).all() transactions = DBSession.query(MoneyTransfer).all() Sprox count, transactions = provider.query(MoneyTransfer) Ming count, transactions = provider.query(MoneyTransfer) transactions = MoneyTransfer.query.find().all() transactions = MoneyTransfer.query.find().all()
  • 15. Experiments Experience ● Starting with a really simple use case made people get comfortable with MongoDB and feel confident enough to start learning more complex features. ● The idea of being possible to use sprox to abstract over the db, making possible to switch back anytime, created a “safety net” idea in people. ● When people feel safe they start experimenting a lot more and learn by themselves.