Python programming databasing



Similar documents
Advanced Tornado TWENTYONE Advanced Tornado Accessing MySQL from Python LAB

Python. Data bases. Marcin Młotkowski. 8th May, 2013

Writing MySQL Scripts With Python's DB-API Interface

Python and MongoDB. Why?

Sharding with postgres_fdw

MongoDB. An introduction and performance analysis. Seminar Thesis

Overview of Databases On MacOS. Karl Kuehn Automation Engineer RethinkDB

Programming in Python V: Accessing a Database

An extension to DBAPI 2.0 for easier SQL queries

Getting Started with MongoDB

HTSQL is a comprehensive navigational query language for relational databases.

Big data and urban mobility

Writing MySQL Scripts with Python DB-API

Riding the Data Wave. New Capabilities New Techniques. Bill Chute Acadiant Limited

MongoDB and Couchbase

The MongoDB Tutorial Introduction for MySQL Users. Stephane Combaudon April 1st, 2014

NOSQL INTRODUCTION WITH MONGODB AND RUBY GEOFF

Open Source Technologies on Microsoft Azure

CSCC09F Programming on the Web. Mongo DB

NoSQL replacement for SQLite (for Beatstream) Antti-Jussi Kovalainen Seminar OHJ-1860: NoSQL databases

Can the Elephants Handle the NoSQL Onslaught?

Enabling development teams to move fast. PostgreSQL at Zalando

An Approach to Implement Map Reduce with NoSQL Databases

Scaling up = getting a better machine. Scaling out = use another server and add it to your cluster.

An Open Source NoSQL solution for Internet Access Logs Analysis

Chapter 9 Java and SQL. Wang Yang wyang@njnet.edu.cn

Introduction to Polyglot Persistence. Antonios Giannopoulos Database Administrator at ObjectRocket by Rackspace

Using SQL Server Management Studio

Perl & NoSQL Focus on MongoDB. Jean-Marie Gouarné jmgdoc@cpan.org

Relational databases and SQL

Databases for text storage

Automating SQL Injection Exploits

Why NoSQL? Your database options in the new non- relational world IBM Cloudant 1

Querying MongoDB without programming using FUNQL

MongoDB Developer and Administrator Certification Course Agenda

Chair of Software Engineering. Java and C# in depth. Carlo A. Furia, Bertrand Meyer. C#: Persistence

Document Oriented Database

pymssql Documentation

Webapps Vulnerability Report

Package RCassandra. R topics documented: February 19, Version Title R/Cassandra interface

College Tuition: Data mining and analysis

Open source framework for interactive data exploration in server based architecture

ENHANCEMENTS TO SQL SERVER COLUMN STORES. Anuhya Mallempati #

MongoDB. Or how I learned to stop worrying and love the database. Mathias Stearn. N*SQL Berlin October 22th, gen

Big Data. Facebook Wall Data using Graph API. Presented by: Prashant Patel Jaykrushna Patel

Visual Statement. NoSQL Data Storage. MongoDB Project. April 10, Bobby Esfandiari Stefan Schielke Nicole Saat

SQL Injection. The ability to inject SQL commands into the database engine through an existing application

Object Relational Database Mapping. Alex Boughton Spring 2011

Python Database Application Programming Interface (DB-API)

ANDROID APPS DEVELOPMENT FOR MOBILE GAME

Weaving Stored Procedures into Java at Zalando

Using Python, Django and MySQL in a Database Course

Advanced Object Oriented Database access using PDO. Marcus Börger

A Brief Introduction to MySQL

Analytics March 2015 White paper. Why NoSQL? Your database options in the new non-relational world

Comparing SQL and NOSQL databases

Django MSSQL Documentation

How SourceForge is Using MongoDB

Introduction to NoSQL Databases and MapReduce. Tore Risch Information Technology Uppsala University

Big Data and Analytics by Seema Acharya and Subhashini Chellappan Copyright 2015, WILEY INDIA PVT. LTD. Introduction to Pig

Database Management System Choices. Introduction To Database Systems CSE 373 Spring 2013

SQL - QUICK GUIDE. Allows users to access data in relational database management systems.

Programming Against Hybrid Databases with Java Handling SQL and NoSQL. Brian Hughes IBM

Database Administration with MySQL

.NET User Group Bern

Harnessing the Potential Raj Nair

NoSQL systems: introduction and data models. Riccardo Torlone Università Roma Tre

Online signature API. Terms used in this document. The API in brief. Version 0.20,

database abstraction layer database abstraction layers in PHP Lukas Smith BackendMedia

MongoDB in the NoSQL and SQL world. Horst Rechner Berlin,

A COMPARATIVE STUDY OF NOSQL DATA STORAGE MODELS FOR BIG DATA

Evaluation of NoSQL databases for large-scale decentralized microblogging

IT2305 Database Systems I (Compulsory)

NO SQL! NO INJECTION?

Please ask questions! Have people used non-relational dbs before? MongoDB?

Customer Bank Account Management System Technical Specification Document

NoSQL web apps. w/ MongoDB, Node.js, AngularJS. Dr. Gerd Jungbluth, NoSQL UG Cologne,


Cloud Scale Distributed Data Storage. Jürmo Mehine

NoSQL, But Even Less Security Bryan Sullivan, Senior Security Researcher, Adobe Secure Software Engineering Team

L7_L10. MongoDB. Big Data and Analytics by Seema Acharya and Subhashini Chellappan Copyright 2015, WILEY INDIA PVT. LTD.

Big Systems, Big Data

Data Intensive Computing Handout 5 Hadoop

Intro to Databases. ACM Webmonkeys 2011

extensible record stores document stores key-value stores Rick Cattel s clustering from Scalable SQL and NoSQL Data Stores SIGMOD Record, 2010

Attacking MongoDB. Firstov Mihail

Introduction to NoSQL and MongoDB. Kathleen Durant Lesson 20 CS 3200 Northeastern University

Write a Foreign Data Wrapper in 15 minutes

Using Object Database db4o as Storage Provider in Voldemort

MySQL Fabric: High Availability Solution for Connector/Python

Transcription:

Finn Årup Nielsen DTU Compute Technical University of Denmark September 22, 2014

Overview Pickle simple format for persistence Key/value store Persistent storage of dictionary-like objects SQL Traditional relational databases NoSQL JSON-like storage Mongo A NoSQL database CouchDB Another NoSQL database Finn Årup Nielsen 1 September 22, 2014

Persistence via pickle String representation of an object (Downey, 2008, section 14.7): >>> alist = [1, 2, 4] >>> import pickle >>> pickle.dumps(alist) # dump with s (lp0\ni1\nai2\nai4\na. Save the object to a file called save.pickle: pickle.dump(alist, open( save.pickle, w )) # dump without s In another Python session you can load the file: >>> import pickle >>> thelist = pickle.load(open( save.pickle )) >>> thelist [1, 2, 4] Finn Årup Nielsen 2 September 22, 2014

... Persistence via pickle cpickle module in Python 2 is faster than pickle module: >>> import pickle, cpickle >>> from time import time as t # or import clock as t for CPU time >>> a = range(100000) >>> t1 = t(); pickle.dump(a, open( save.pkl, w )); t() - t1 0.65437793731689453 >>> t1 = t(); cpickle.dump(a, open( save.pkl, w )); t() - t1 0.1010589599609375 >>> t1 = t(); cpickle.dump(a, open( save.pkl, w ), 2); t() - t1 0.030821800231933594 The last cpickle example uses a faster protocol for encoding. Note: Not all Python code can be pickled directly Finn Årup Nielsen 3 September 22, 2014

Why not use JSON for persistence? For simple Python objects you can also use JSON >>> import cpickle >>> import json >>> from time import time as t # or import clock as t for CPU time >>> a = range(100000) >>> t1 = t(); cpickle.dump(a, open( save.pkl, w )); t() - t1 0.05009317398071289 >>> t1 = t(); json.dump(a, open( save.json, w )); t() - t1 0.09607791900634766 though in this case JSON is a bit slower, but other programs than Python can read it, and reading a apparently faster (for default protocol) >>> t1 = t(); b = cpickle.load(open( save.pkl )); t() - t1 0.06250786781311035 >>> t1 = t(); c = json.load(open( save.json )); t() - t1 0.013430118560791016 Finn Årup Nielsen 4 September 22, 2014

Why not use JSON for persistence? Insecure against erroneous or maliciously constructed data, e.g., Nadia Alramli s example on why pickle is dangerous: import pickle pickle.loads("cos\nsystem\n(s ls ~ \ntr.") # This will run: ls ~ JSON is more secure, though cannot do (Martelli et al., 2005, sect. 7.4): >>> class MyClass():... def init (self, v): self.value = v >>> mc = MyClass(4) >>> pickle.dump(mc, open( save.pickle, w )) >>> reloaded = pickle.load(open( save.pickle )) >>> reloaded.value 4 Finn Årup Nielsen 5 September 22, 2014

Serialized JSON and Pickle can also be serialized and transmitted. Finn Årup Nielsen 6 September 22, 2014

... Persistence via pickle What is the result of this pickle: example.pickle? (Do not unpickle files, i.e., load pickle files, from the net unless you trust them!) Finn Årup Nielsen 7 September 22, 2014

Persistent dictionary Simple Python-based persistent dictionary with shelve: >>> import shelve >>> she = shelve.open( test.she, c ) >>> she[ stupid ] = -3 >>> she[ funny ] = 3 >>> she.close() In another later Python session the stored items can be accessed: >>> import shelve >>> she = shelve.open( test.she, c ) >>> for k, v in she.items():... print k, v funny 3 stupid -3 Finn Årup Nielsen 8 September 22, 2014

Other key/value store Berkeley DB (here with Evolution addressbook): >>> import bsddb # Release 4 >>> filename =.evolution/addressbook/local/system/addressbook.db >>> db = bsddb.hashopen(filename, r ) # Open for reading >>> for k, v in db.iteritems(): print("%s --> %s" % (k, v)) pas-id-469f320f00000000 --> BEGIN:VCARD VERSION:3.0 EMAIL;TYPE=WORK:fn@imm.dtu.dk X-EVOLUTION-BLOG-URL:http://fnielsen.posterous.com... >>> db.close() # Close the database Finn Årup Nielsen 9 September 22, 2014

shelve manipulation What is the sum of the values where the initial letter in the keys are a in this shelve: example.shelve? Finn Årup Nielsen 10 September 22, 2014

SQL Python overview Python can work with relational database management systems, such as MySQL, PostgreSQL (both client-server-based) and SQLite (lightweight) The databases can be accessed by: 1. Specialized modules: MySQLdb, psycocg and sqlite. Because these modules implement the DB API 2.0 standard the interfaces are similar. 2. Generic connectivity with ODBC: pyodbc 3. With an object-relational mapper (mediator between Python classes and SQL tables): sqlobject (simple) sqlalchemy (more complex) and models in the Django web framework (from django.db import models),... On top of SQLAlchemy: elixir. Finn Årup Nielsen 11 September 22, 2014

DB API 2.0-like SQL connectivity steps import database module connect to the database Acquire cursor. With connection.cursor() execute SQL statement. With execute(), executemany() or executescript() fetch the results. With fetchone(), fetchmany() or fetchall() commit changes. connection.commit() close connection. Use connection.close() or the with keyword. Finn Årup Nielsen 12 September 22, 2014

DB API 2.0-like SQL connectivity Import module and get a connection. For SQLite no host, user and password is necessary to get a connection, the database is just a single file. >>> from pysqlite2 import dbapi2 as db >>> connection = db.connect("courses.sqlite") Get cursor and create a table called courses in the SQL database with an SQL statement issued with the execute method: >>> cursor = connection.cursor() >>> cursor.execute("""create TABLE courses ( number CHAR(5) PRIMARY KEY, name CHAR(100), ects FLOAT);""") Finn Årup Nielsen 13 September 22, 2014

Python SQL Insertion Insert some explicit data into the courses table: >>> cursor.execute("""insert INTO courses VALUES ("02820", "Python programming", 5);""") >>> connection.commit() Parameterized input with a Python variable (courses): >>> courses = ("02457", "Nonlinear Signal Processing", 10) >>> cursor.execute("insert INTO courses VALUES (?,?,?);", courses) >>> connection.commit() Parameterized insertion of multiple rows with executemany: >>> courses = [("02454", "Introduction to Cognitive Science", 5), ("02451", "Digital Signal Processing", 10)] >>> cursor.executemany("insert INTO courses VALUES (?,?,?);", courses) >>> connection.commit() Finn Årup Nielsen 14 September 22, 2014

Python SQL fetching data Return one row at a time with fetchone: >>> cursor.execute("select * FROM courses;") >>> cursor.fetchone() (u 02820, u Python programming, 5.0) Or use the cursor as iterator: >>> cursor.execute("select * FROM courses;") >>> for row in cursor: print(row) # The 4 rows are printed Get all returned data into a Python variable >>> cursor.execute("select * FROM courses ORDER BY number LIMIT 2;") >>> c = cursor.fetchall() [(u 02451, u Digital Signal Processing, 10.0), (u 02454, u Introduction to Cognitive Science, 5.0)] Finn Årup Nielsen 15 September 22, 2014

Python SQL paramstyle differences With pysqlite, tuple and question mark: >>> param = { ects : 10.0} >>> cursor.execute("select name FROM courses WHERE ects =?", (param[ ects ],)) >>> cursor.fetchall() [(u Nonlinear Signal Processing,), (u Digital Signal Processing,)] Equivalent query with pysqlite, dictionary and named parameter: >>> cursor.execute("select name FROM courses WHERE ects = :ects", param) With MySQLdb, tuple and %s >>> cursor.execute("select name FROM courses WHERE ects = %s", (param[ ects ],)) Finn Årup Nielsen 16 September 22, 2014

Bad and dangerous use of SQL!!! >>> from pysqlite2 import dbapi2 as db >>> connection = db.connect("test.sqlite") >>> cursor = connection.cursor() >>> cursor.execute("create TABLE students ( password, name );") >>> cursor.execute("""insert INTO students VALUES ("1234", "Finn");""") >>> cursor.execute("""select * FROM students;""") >>> cursor.fetchall() [(u 1234, u Finn )] >>> pw = dummy", (SELECT password FROM students WHERE name = "Finn")); -- >>> name = "dummy" >>> sql = INSERT INTO students VALUES ("%s", "%s"); % (pw, name) >>> cursor.execute(sql) >>> cursor.execute( SELECT * FROM students; ) >>> cursor.fetchall() [(u 1234, u Finn ), (u dummy, u 1234 )] # Password revealed in name! (And don t store literal passwords in databases hash it) Finn Årup Nielsen 17 September 22, 2014

sqlite manipulation An sqlite file contains a table called data with columns value and type. What is the average of the value s conditioned on the type for this sqlite file: example.sqlite? Finn Årup Nielsen 18 September 22, 2014

Object-relational mapping One-to-one mapping between Python class and SQL table. from sqlobject import * import os connection = sqlite: + os.path.abspath( politicians.sqlite ) class Politician(SQLObject): name = UnicodeCol(length=60, notnone=true) partyletter = UnicodeCol(length=1) votes = IntCol() birthday = DateCol() Create table: Politician.createTable() Now the politicians.sqlite SQLite database file has been written. Finn Årup Nielsen 19 September 22, 2014

Insert a couple of politicians in the database: >>> Politician(name=u"Lars Løkke Rasmussen", partyletter="v", votes=21384, birthday="1964-05-15") >>> Politician(name=u"Villy Søvndal", partyletter="f", votes=33046, birthday="1952-04-04") >>> Politician(name=u"Pia Kjærsgaard", partyletter="o", votes=47611, birthday="1947-02-23") There is an id INT PRIMARY KEY AUTO_INCREMENT column added. Simple data fetch based on the id: >>> Politician.get(1).name u Lars L\xf8kke Rasmussen Select with condition on Politicians: >>> [p.name for p in Politician.select(Politician.q.votes > 30000, orderby=politician.q.birthday)] [u Pia Kj\xe6rsgaard, u Villy S\xf8vndal ] Finn Årup Nielsen 20 September 22, 2014

Another example with numerical aggregation (summing, averaging): import os from sqlobject import * connection = sqlite: + os.path.abspath( pima.db ) class Pima(SQLObject): npreg = IntCol() bmi = FloatCol() type = EnumCol(enumValues=["Yes", "No"]) Pima.createTable() Pima(npreg=6, bmi=33.6, type="yes") Pima(npreg=1, bmi=26.6, type="no") Pima(npreg=1, bmi=28.1, type="no") Finn Årup Nielsen 21 September 22, 2014

>>> Pima.selectBy(type= No ).avg( bmi ) 27.35 More complex queries are not necessarily pretty: >>> c = Pima._connection >>> c.queryall("select AVG(npreg), AVG(bmi), type FROM pima GROUP BY type") [(1.0, 27.35, No ), (6.0, 33.6, Yes )] The complex query using sqlbuilder: >>> from sqlobject.sqlbuilder import * >>> select = Select([func.AVG(Pima.q.npreg), func.avg(pima.q.bmi), Pima.q.type], groupby=pima.q.type) >>> query = Pima.sqlrepr(select) >>> Pima._connection.queryAll(query) [(1.0, 27.35, No ), (6.0, 33.6, Yes )] Finn Årup Nielsen 22 September 22, 2014

Which ORM? Finn Årup Nielsen 23 September 22, 2014

NoSQL NoSQL = Databases with no SQL functionality Examples: CouchDB, MongoDB, Cassandra,... May have good capabilities for replication, high availability, sharding.. May lack more than simple query mechanisms.. (You can have NoSQL functionality in SQL databases) Finn Årup Nielsen 24 September 22, 2014

MongoDB MongoDB, http://www.mongodb.org/, stores JSON-like objects.. 2GB limitation on 32-bit platforms.. $ mongod & # The database server $ mongo # The database client ( test database default) > use test > book = { title : "Kongens Fald", author : "Johannes V. Jensen" } > db.books.save(book) > book = { title : "Himmerlandshistorier", author : "Johannes V. Jensen" } > db.books.save(book) > book = { title : "Eventyr", author : "H. C. Andersen" } > db.books.save(book) Finn Årup Nielsen 25 September 22, 2014

MongoDB query > db.books.find() # Find all { "_id" : ObjectId("4c82a97c6600b82f5cdcb93b"), "title" : "Kongens Fald", "author" : "Johannes V. Jensen" } { "_id" : ObjectId("4c82a98c6600b82f5cdcb93c"), "title" : "Himmerlandshistorier", "author" : "Johannes V. Jensen" } { "_id" : ObjectId("4c82a9996600b82f5cdcb93d"), "title" : "Eventyr", "author" : "H. C. Andersen" } > db.books.find({ author : "Johannes V. Jensen" }) # Find a specific { "_id" : ObjectId("4c82a97c6600b82f5cdcb93b"), "title" : "Kongens Fald", "author" : "Johannes V. Jensen" } { "_id" : ObjectId("4c82a98c6600b82f5cdcb93c"), "title" : "Himmerlandshistorier", "author" : "Johannes V. Jensen" } Finn Årup Nielsen 26 September 22, 2014

MongoDB with Python $ sudo pip install pymongo # Installation with "pip" # Installation requires "python-dev" $ mongod & # Starting server $ python # and into Python >>> import pymongo >>> connection = pymongo.connection() # help(pymongo.connection) >>> db = connection.test >>> books = db.books # "books" is a "collection" >>> book = {"title": "Kongens Fald", "author": "Johannes V. Jensen" } >>> books.insert(book) >>> morebooks = [{"title": "Himmerlandshistorier", "author": "Johannes V. Jensen" }, {"title": "Eventyr", "author": "H. C. Andersen"}, {"title": "Biblen"}] >>> books.insert(morebooks) Finn Årup Nielsen 27 September 22, 2014

MongoDB with Python Getting back information from the Mongo server: >>> for book in books.find():... print(book.get("author", "Missing author")) Johannes V. Jensen Johannes V. Jensen H. C. Andersen Missing author Updating a field: >>> books.update({"title": "Himmerlandshistorier"}, {"$set": {"isbn": "8702040638"}}) Finn Årup Nielsen 28 September 22, 2014

Twitter, Python and MongoDB (outdated) import getpass, pymongo, simplejson, urllib password = getpass.getpass() # get password for "fnielsen2" user url = "http://fnielsen2:" + password + \ "@stream.twitter.com/1/statuses/sample.json" connection = pymongo.connection() db = connection.twitter tweets = db.tweets for tweet in urllib.urlopen(url): oid = tweets.insert(simplejson.loads(tweet)) print(tweets.count()) As Twitter returns JSON we can directly convert it to a Python structure and further to an entry in Mongo. (Note: Twitter is changing its authentication) Finn Årup Nielsen 29 September 22, 2014

>>> tweets.find_one().keys() [u favorited, u retweet_count, u in_reply_to_user_id, u contributors, u truncated, u text, u created_at, u retweeted, u coordinates, u entities, u in_reply_to_status_id, u place, u source, u in_reply_to_screen_name, u _id, u geo, u id, u user ] >>> tweets.find_one()[ user ].keys() [u follow_request_sent, u profile_use_background_image, u id, u verified, u profile_sidebar_fill_color, u profile_text_color, u followers_count, u profile_sidebar_border_color, u location, u profile_background_color, u listed_count, u utc_offset, u statuses_count, u description, u friends_count, u profile_link_color, u profile_image_url, u notifications, u show_all_inline_media, u geo_enabled, u profile_background_image_url, u screen_name, u lang, u profile_background_tile, u favourites_count, u name, u url, u created_at, u contributors_enabled, u time_zone, u protected, u following ] Finn Årup Nielsen 30 September 22, 2014

Python MongoDB: updating a field import sys reload(sys) sys.setdefaultencoding( utf-8 ) # Load a dictionary with words scored according to how English # -3 not English, +3 English, 0 unknown or might or might not be English filename = /home/fn/fnielsen/data/nielsen2010responsible_english.csv englishwords = dict(map(lambda (k,v): (k,int(v)), [line.split() for line in open(filename)])) for tweet in tweets.find({"delete": {"$exists": False}}): englishness = sum(map(lambda word: englishwords.get(word.lower(),0), tweet[ text ].split())) tweet[ englishness ] = englishness # Add a new field oid = tweets.save(tweet) # Overwrite the element Finn Årup Nielsen 31 September 22, 2014

MongoDB queries in Python >>> tweets.find_one({"englishness": {"$gt": 15}})[ text ] u @ItsAnnaJayce HEY babs! could you please take one min to follow @kyleinju5tice it would be appreciated thankyouuu:) <3 #LLWFH >>> tweets.find_one({"englishness": {"$lt": -15}})[ text ] u eu quero sorvete e shampoo mas minha mae fica enrrolando na cama e at\xe9 agora nao foi comprar.-. >>> tweets.find_one({"englishness": 0})[ text ] u"@rafiniits axo mtmtmt boom - UYSAGDYGAYSUG " See also http://www.mongodb.org/display/docs/advanced+queries Finn Årup Nielsen 32 September 22, 2014

CouchDB and Python CouchDB http://couchdb.apache.org/ RESTful, JSON.. $ couchdb $ python >>> import couchdb, couchdb.schema, urllib >>> urllib.urlopen( http://localhost:5984/ ).read() # RESTful {"couchdb":"welcome","version":"0.10.0"}\n >>> server = couchdb.client.server() # Default http://localhost:5984 >>> db = server.create( books ) >>> urllib.urlopen( http://localhost:5984/_all_dbs ).read() ["books"]\n Inserting three books: >>> did = db.create({"author": "H. C. Andersen", "title": "Eventyr"}) >>> did = db.create({"title": "Biblen"}) >>> did = db.create({"author": "Johannes V. Jensen", "title": "Kongens Fald"}) Finn Årup Nielsen 33 September 22, 2014

Query CouchDB with Python Simple getting of fields: >>> for book in db: print(db[book].get("author", "Missing author")) H. C. Andersen Johannes V. Jensen Missing author Query via a map function written as a JavaScript function: >>> fun = """function(book) { if (book.author == H. C. Andersen )... emit(book._id, book) }""" >>> db.query(fun).rows[0][ value ][ title ] Eventyr Finn Årup Nielsen 34 September 22, 2014

CouchDB updating a field with Python >>> fun = "function(b) { if (b.title == Kongens Fald ) emit(b._id, b)}" >>> result = db.query(fun).rows[0] >>> did, book = result["key"], result["value"] >>> book["isbn"] = "9788702058239" >>> db[did] = book Finn Årup Nielsen 35 September 22, 2014

More information Introduction to SQLAlchemy, video tutorial with Mike Bayer from Pycon 2013. Finn Årup Nielsen 36 September 22, 2014

Summary Pickle is the primary format for storing and serializing Python objects, and you can use pickle module or the faster cpickle module for dumping and loading. Problems with pickle is that it is for Python only and that you can have dangerous code in it. There are interfaces to database management systems Key/value store: shelve, Berkeley DB Relational databases: Either directly (e.g., by MySQLdb), or generic (pyodbc), or ORM. NoSQL access also available, e.g., MongoDB, CouchDB,... Usually a good idea to use ORM, but beware that ORM can yield large number of SQL queries from one ORM query. Finn Årup Nielsen 37 September 22, 2014

References References Downey, A. (2008). Think Python. Green Tea Press, Needham, Massachusetts, version 1.1.15 edition. Martelli, A., Ravenscroft, A. M., and Ascher, D., editors (2005). Python Cookbook. O Reilly, Sebastopol, California, 2nd edition. Finn Årup Nielsen 38 September 22, 2014