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

What's hot

Node.js - Best practices
Node.js  - Best practicesNode.js  - Best practices
Node.js - Best practices
Felix Geisendörfer
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
Supercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamicSupercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamic
Ian Robertson
 
Vue.js + Django - configuración para desarrollo con webpack y HMR
Vue.js + Django - configuración para desarrollo con webpack y HMRVue.js + Django - configuración para desarrollo con webpack y HMR
Vue.js + Django - configuración para desarrollo con webpack y HMR
Javier Abadía
 
Python在豆瓣的应用
Python在豆瓣的应用Python在豆瓣的应用
Python在豆瓣的应用
Qiangning Hong
 
FwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.jsFwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.js
Timur Shemsedinov
 
JavaScript 101
JavaScript 101JavaScript 101
JavaScript 101
ygv2000
 
The State of JavaScript
The State of JavaScriptThe State of JavaScript
The State of JavaScript
Domenic Denicola
 
Powerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesPowerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best Practices
Dragos Ionita
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
MongoDB
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboy
Kenneth Geisshirt
 
This upload requires better support for ODP format
This upload requires better support for ODP formatThis upload requires better support for ODP format
This upload requires better support for ODP format
Forest Mars
 
Building High Performance Web Applications and Sites
Building High Performance Web Applications and SitesBuilding High Performance Web Applications and Sites
Building High Performance Web Applications and Sites
goodfriday
 
Dgeni documentation generator
Dgeni   documentation generatorDgeni   documentation generator
Dgeni documentation generator
Peter Darwin
 
Introduction to Grails Framework
Introduction to Grails FrameworkIntroduction to Grails Framework
Introduction to Grails Framework
PT.JUG
 
All you need to know about the JavaScript event loop
All you need to know about the JavaScript event loopAll you need to know about the JavaScript event loop
All you need to know about the JavaScript event loop
Saša Tatar
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
Jeado Ko
 
Svcc Building Rich Applications with Groovy's SwingBuilder
Svcc Building Rich Applications with Groovy's SwingBuilderSvcc Building Rich Applications with Groovy's SwingBuilder
Svcc Building Rich Applications with Groovy's SwingBuilder
Andres Almiray
 

What's hot (20)

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

Similar to From SQLAlchemy to Ming with TurboGears2

Native Java with GraalVM
Native Java with GraalVMNative Java with GraalVM
Native Java with GraalVM
Sylvain Wallez
 
Get together on getting more out of typescript &amp; angular 2
Get together on getting more out of typescript &amp; angular 2Get together on getting more out of typescript &amp; angular 2
Get together on getting more out of typescript &amp; angular 2
Ruben Haeck
 
Dynamic Tracing of your AMP web site
Dynamic Tracing of your AMP web siteDynamic Tracing of your AMP web site
Dynamic Tracing of your AMP web site
Sriram Natarajan
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
Yakov Fain
 
Robust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time ChecksRobust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time Checks
Stoyan Nikolov
 
WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows
WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows
WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows
T.Rob Wyatt
 
L Fu - Dao: a novel programming language for bioinformatics
L Fu - Dao: a novel programming language for bioinformaticsL Fu - Dao: a novel programming language for bioinformatics
L Fu - Dao: a novel programming language for bioinformatics
Jan Aerts
 
Why you should be using structured logs
Why you should be using structured logsWhy you should be using structured logs
Why you should be using structured logs
Stefan Krawczyk
 
Writing Apps with HotCocoa and MacRuby
Writing Apps with HotCocoa and MacRubyWriting Apps with HotCocoa and MacRuby
Writing Apps with HotCocoa and MacRuby
Renzo Borgatti
 
Django tricks (2)
Django tricks (2)Django tricks (2)
Django tricks (2)
Carlos Hernando
 
Monitoring MySQL with DTrace/SystemTap
Monitoring MySQL with DTrace/SystemTapMonitoring MySQL with DTrace/SystemTap
Monitoring MySQL with DTrace/SystemTap
Padraig O'Sullivan
 
Ember-CLI Blueprints for fun and profit
Ember-CLI Blueprints for fun and profitEmber-CLI Blueprints for fun and profit
Ember-CLI Blueprints for fun and profit
Salesforce Engineering
 
CDK Meetup: Rule the World through IaC
CDK Meetup: Rule the World through IaCCDK Meetup: Rule the World through IaC
CDK Meetup: Rule the World through IaC
smalltown
 
Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...
Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...
Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...
Amazon Web Services
 
E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)
E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)
E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)
Valeriy Kravchuk
 
End to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaEnd to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux Saga
Babacar NIANG
 
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
idsecconf
 
What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)
What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)
What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)
Igalia
 
BarcelonaJUG2016: walkmod: how to run and design code transformations
BarcelonaJUG2016: walkmod: how to run and design code transformationsBarcelonaJUG2016: walkmod: how to run and design code transformations
BarcelonaJUG2016: walkmod: how to run and design code transformations
walkmod
 
C# 6.0 Preview
C# 6.0 PreviewC# 6.0 Preview
C# 6.0 Preview
Fujio Kojima
 

Similar to From SQLAlchemy to Ming with TurboGears2 (20)

Native Java with GraalVM
Native Java with GraalVMNative Java with GraalVM
Native Java with GraalVM
 
Get together on getting more out of typescript &amp; angular 2
Get together on getting more out of typescript &amp; angular 2Get together on getting more out of typescript &amp; angular 2
Get together on getting more out of typescript &amp; angular 2
 
Dynamic Tracing of your AMP web site
Dynamic Tracing of your AMP web siteDynamic Tracing of your AMP web site
Dynamic Tracing of your AMP web site
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
 
Robust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time ChecksRobust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time Checks
 
WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows
WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows
WMQ Toolbox: 20 Scripts, One-liners, & Utilities for UNIX & Windows
 
L Fu - Dao: a novel programming language for bioinformatics
L Fu - Dao: a novel programming language for bioinformaticsL Fu - Dao: a novel programming language for bioinformatics
L Fu - Dao: a novel programming language for bioinformatics
 
Why you should be using structured logs
Why you should be using structured logsWhy you should be using structured logs
Why you should be using structured logs
 
Writing Apps with HotCocoa and MacRuby
Writing Apps with HotCocoa and MacRubyWriting Apps with HotCocoa and MacRuby
Writing Apps with HotCocoa and MacRuby
 
Django tricks (2)
Django tricks (2)Django tricks (2)
Django tricks (2)
 
Monitoring MySQL with DTrace/SystemTap
Monitoring MySQL with DTrace/SystemTapMonitoring MySQL with DTrace/SystemTap
Monitoring MySQL with DTrace/SystemTap
 
Ember-CLI Blueprints for fun and profit
Ember-CLI Blueprints for fun and profitEmber-CLI Blueprints for fun and profit
Ember-CLI Blueprints for fun and profit
 
CDK Meetup: Rule the World through IaC
CDK Meetup: Rule the World through IaCCDK Meetup: Rule the World through IaC
CDK Meetup: Rule the World through IaC
 
Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...
Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...
Monitoring as Code: Getting to Monitoring-Driven Development - DEV314 - re:In...
 
E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)
E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)
E bpf and dynamic tracing for mariadb db as (mariadb day during fosdem 2020)
 
End to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaEnd to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux Saga
 
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
 
What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)
What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)
What's new with JavaScript in GNOME: The 2020 edition (GUADEC 2020)
 
BarcelonaJUG2016: walkmod: how to run and design code transformations
BarcelonaJUG2016: walkmod: how to run and design code transformationsBarcelonaJUG2016: walkmod: how to run and design code transformations
BarcelonaJUG2016: walkmod: how to run and design code transformations
 
C# 6.0 Preview
C# 6.0 PreviewC# 6.0 Preview
C# 6.0 Preview
 

More from Alessandro Molina

PyCon Ireland 2022 - PyArrow full stack.pdf
PyCon Ireland 2022 - PyArrow full stack.pdfPyCon Ireland 2022 - PyArrow full stack.pdf
PyCon Ireland 2022 - PyArrow full stack.pdf
Alessandro Molina
 
EP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
EP2016 - Moving Away From Nodejs To A Pure Python Solution For AssetsEP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
EP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
Alessandro Molina
 
EuroPython 2015 - Storing files for the web is not as straightforward as you ...
EuroPython 2015 - Storing files for the web is not as straightforward as you ...EuroPython 2015 - Storing files for the web is not as straightforward as you ...
EuroPython 2015 - Storing files for the web is not as straightforward as you ...
Alessandro Molina
 
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATESPyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
Alessandro Molina
 
PyConIT6 - Messing up with pymongo for fun and profit
PyConIT6 - Messing up with pymongo for fun and profitPyConIT6 - Messing up with pymongo for fun and profit
PyConIT6 - Messing up with pymongo for fun and profitAlessandro Molina
 
PyConFR 2014 - DEPOT, Story of a file.write() gone wrong
PyConFR 2014 - DEPOT, Story of a file.write() gone wrongPyConFR 2014 - DEPOT, Story of a file.write() gone wrong
PyConFR 2014 - DEPOT, Story of a file.write() gone wrong
Alessandro Molina
 
PyConUK 2014 - PostMortem Debugging and Web Development Updated
PyConUK 2014 - PostMortem Debugging and Web Development UpdatedPyConUK 2014 - PostMortem Debugging and Web Development Updated
PyConUK 2014 - PostMortem Debugging and Web Development Updated
Alessandro Molina
 
Post-Mortem Debugging and Web Development
Post-Mortem Debugging and Web DevelopmentPost-Mortem Debugging and Web Development
Post-Mortem Debugging and Web Development
Alessandro Molina
 
MongoTorino 2013 - BSON Mad Science for fun and profit
MongoTorino 2013 - BSON Mad Science for fun and profitMongoTorino 2013 - BSON Mad Science for fun and profit
MongoTorino 2013 - BSON Mad Science for fun and profit
Alessandro Molina
 
PyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with MingPyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with Ming
Alessandro Molina
 
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
Alessandro Molina
 
EuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears TrainingEuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears Training
Alessandro Molina
 
PyGrunn2013 High Performance Web Applications with TurboGears
PyGrunn2013  High Performance Web Applications with TurboGearsPyGrunn2013  High Performance Web Applications with TurboGears
PyGrunn2013 High Performance Web Applications with TurboGears
Alessandro Molina
 
Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2Alessandro Molina
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsAlessandro Molina
 

More from Alessandro Molina (15)

PyCon Ireland 2022 - PyArrow full stack.pdf
PyCon Ireland 2022 - PyArrow full stack.pdfPyCon Ireland 2022 - PyArrow full stack.pdf
PyCon Ireland 2022 - PyArrow full stack.pdf
 
EP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
EP2016 - Moving Away From Nodejs To A Pure Python Solution For AssetsEP2016 - Moving Away From Nodejs To A Pure Python Solution For Assets
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 ...
EuroPython 2015 - Storing files for the web is not as straightforward as you ...EuroPython 2015 - Storing files for the web is not as straightforward as you ...
EuroPython 2015 - Storing files for the web is not as straightforward as you ...
 
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATESPyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
PyConIT6 - MAKING SESSIONS AND CACHING ROOMMATES
 
PyConIT6 - Messing up with pymongo for fun and profit
PyConIT6 - Messing up with pymongo for fun and profitPyConIT6 - Messing up with pymongo for fun and profit
PyConIT6 - Messing up with pymongo for fun and profit
 
PyConFR 2014 - DEPOT, Story of a file.write() gone wrong
PyConFR 2014 - DEPOT, Story of a file.write() gone wrongPyConFR 2014 - DEPOT, Story of a file.write() gone wrong
PyConFR 2014 - DEPOT, Story of a file.write() gone wrong
 
PyConUK 2014 - PostMortem Debugging and Web Development Updated
PyConUK 2014 - PostMortem Debugging and Web Development UpdatedPyConUK 2014 - PostMortem Debugging and Web Development Updated
PyConUK 2014 - PostMortem Debugging and Web Development Updated
 
Post-Mortem Debugging and Web Development
Post-Mortem Debugging and Web DevelopmentPost-Mortem Debugging and Web Development
Post-Mortem Debugging and Web Development
 
MongoTorino 2013 - BSON Mad Science for fun and profit
MongoTorino 2013 - BSON Mad Science for fun and profitMongoTorino 2013 - BSON Mad Science for fun and profit
MongoTorino 2013 - BSON Mad Science for fun and profit
 
PyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with MingPyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with Ming
 
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
EuroPython 2013 - FAST, DOCUMENTED AND RELIABLE JSON BASED WEBSERVICES WITH P...
 
EuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears TrainingEuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears Training
 
PyGrunn2013 High Performance Web Applications with TurboGears
PyGrunn2013  High Performance Web Applications with TurboGearsPyGrunn2013  High Performance Web Applications with TurboGears
PyGrunn2013 High Performance Web Applications with TurboGears
 
Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
 

Recently uploaded

Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
Matthew Sinclair
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
ThomasParaiso2
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
Pierluigi Pugliese
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
Neo4j
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
SOFTTECHHUB
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
Peter Spielvogel
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
James Anderson
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
Neo4j
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 

Recently uploaded (20)

Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 

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.