A tutorial on deploying ORM libraries on Python's Django framework _python

Source: Internet
Author: User
Tags flush object object sqlite sqlite database create database ruby on rails in python

Python ORM Overview

As a wonderful language, Python has many ORM libraries in addition to SQLAlchemy. In this article, we'll look at a few popular alternative ORM libraries to better spy on the Python ORM situation. By writing a script to read and write 2 tables, person, and address to a simple database, we can better understand the pros and cons of each ORM library.

Sqlobject

Sqlobject is a Python ORM that maps objects between SQL databases and Python. Thanks to its activerecord pattern, similar to Ruby on Rails, it has become increasingly popular in the programming community. The first Sqlobject was released in October 2002. It follows the LGPL license.

In Sqlobject, a database concept is mapped to Python in a way that is very similar to slqalchemy, with tables mapped to classes, rows as instances and fields as attributes. It also provides a query language based on Python objects, which makes SQL more abstract, providing a database agnostic for Applications (application and database separation)

$ pip Install sqlobject downloading/unpacking sqlobject downloading sqlobject-1.5.1.tar.gz (276kB): 276kB downloaded Runn ing setup.py egg_info for package sqlobject warning:no files found matching ' *.html ' warning:no files found matching ' *.css ' warning:no files found matching ' docs/*.html ' warning:no files found matching ' *.py ' under directory ' tests ' requ Irement already satisfied (use--upgrade to upgrade): formencode>=1.1.1 in/users/xiaonuogantan/python2-workspace/ Lib/python2.7/site-packages (from Sqlobject) installing collected packages:sqlobject Running setup.py install for Sqlobj ECT changing mode of build/scripts-2.7/sqlobject-admin from 644 to 755 changing mode of Build/scripts-2.7/sqlobject-conver Tolduri from 644 to 755 warning:no files found matching ' *.html ' warning:no files found matching ' *.css ' Warning:no f Iles found matching ' docs/*.html ' warning:no files found matching ' *.py ' under directory ' tests ' changing mode of/users/ Xiaonuogantan/python2-workspacE/bin/sqlobject-admin to 755 changing mode Of/users/xiaonuogantan/python2-workspace/bin/sqlobject-convertolduri to  755 successfully installed Sqlobject cleaning up ... >>> from sqlobject import Stringcol, Sqlobject, ForeignKey,
Sqlhub, Connectionforuri >>> sqlhub.processconnection = Connectionforuri (' sqlite:/:memory: ') >>> >>> class Person (sqlobject): ... name = Stringcol () ... >>> class address (Sqlobject): ... address = Stri
 Ngcol () ... person = foreignkey (' person ') ... >>> person.createtable () [] >>> address.createtable () []

The code above creates 2 simple tables: person and address. To create and insert records into these 2 tables, we simply instantiate a person instance and an address instance:

>>> p = person (name= "person")
>>> a = Address (address= ' address ', person=p)
>>> p
 
>>> a
 
<address>

To get or retrieve new records, we associate the Magic Q object with the person and address class:


>>> persons = Person.select (Person.q.name = = ' person ')
>>> persons
 
>>> list ( Persons)
[]
>>> p1 = persons[0]
>>> p1 = = P
True
>>> addresses = Address.select (Address.q.person = = p1)
>>> addresses
 
>>> list (addresses)
[
 
<ADDRESS>]
>>> a1 = addresses[0]
>>> a1 = = a
True
 
Storm

Storm is a Python ORM that maps objects between a single or multiple databases and Python. To support dynamic storage and retrieval of object information, it allows developers to build complex queries across data tables. It was developed in Python by the company canonical company behind Ubuntu, used in Launchpad and landscape applications, and later released as free software in 2007. This project is issued under the LGPL license and the code contributor must be copyrighted to the canonical company.

Like SQLAlchemy and Sqlobject, Storm maps tables to classes, rows to instances and fields to properties. Compared to 2 other libraries, the table class in Stom does not need to be a subclass of a framework-specific base class. In SQLAlchemy, each table class is a subclass of Sqlalchemy.ext.declarative.declarative_bas. In Sqlojbect, each table class is sqlobject. Sqlobject subclass of the class.

Like SQLAlchemy, the Storm Store object is like an agent for the backend database, all operations cached in memory, and submitted to the database when the submission method is invoked on the Store. Each store holds its own collection of Python database object mappings, just like a SQLAlchemy session holds a different collection of Python objects.

The specified version of Storm can be downloaded from the download page. In this article, the sample code is written using the 0.20 version of Storm.

>>> from storm.locals import Int, Reference, Unicode, Create_database, Store
>>>
>> >
>>> db = Create_database (' SQLite: ')
>>> store = store (db)
>>>
> >>
>>> class Person (object):
... __storm_table__ = ' person '
... id = Int (primary=true)
... name = Unicode () ...
>>>
>>> class Address (object):
... __storm_table__ = ' address '
... id = Int (primary= True)
... address = Unicode () ...
person_id = Int () ... person
= Reference (person_id, person.id)
...

The code above creates a SQLite memory database and then uses the store to refer to the database object. A storm store resembles a SQLAlchemy Dbsession object that manages the lifecycle of an instance object that is attached to it. For example, the following code creates a person and an address, and then inserts records by refreshing the store.

>>> Store.execute ("CREATE TABLE person" ...) "(ID INTEGER PRIMARY KEY, name VARCHAR)") >>> Store.execute ("CREATE TABLE address" ...) "(Id integer PRIMARY KEY, Address VARCHAR, person_id integer," ... "FOREIGN KEY (person_id) REFERENCES person (ID)") >>> person = person () >>> person.name = U ' Person ' &G t;>> Print person >>> print "%r,%r"% (person.id, person.name) None, u ' person ' # Notice that person.id I
s None since the person instance isn't attached to a valid database store yet. >>> store.add >>> print "%r,%r"% (person.id, person.name) None, u ' person ' # Since the store
Hasn ' t flushed the person instance to the SQLite database yet, Person.id is still None.  >>> Store.flush () >>> print "%r,%r"% (Person.id, person.name) 1, u ' person ' * Now the store has flushed
The person instance, we got a ID value for person. >>> address = address () >>> Address.person = persOn >>> address.address = ' address ' >>> print '%r,%r,%r '% (address.id, Address.person, address.address None,, ' address ' >>> Address.person = person True >>> store.add (address) >>> Store.flush (
 >>> print "%r,%r,%r"% (Address.id, Address.person, address.address) 1,, ' address '

To get or retrieve the inserted person and address object, we call Store.find () to query:


>>> person = store.find (person, person.name = U ' person '). One ()
>>> print "%r,%r"% (Person.id, per Son.name)
1, u ' person '
>>> store.find (address, Address.person = person). One ()
 
>>> Address = Store.find (address, Address.person = person). One ()
>>> print "%r,%r"% (Address.id, address.addr ESS)
1, u ' address '

Django ORM

Django is a free open source, tightly embedded ORM to its System Web application framework. Django became more popular after its first release, thanks to its easy-to-use web-ready features. It was released under the BSD license in July 2005. Because Django's ORM is tightly embedded in the web framework, it is not recommended to use ORM in a stand-alone, non-Django Python project.

Django, one of the most popular Python web frames, has a unique ORM. Compared to SQLAlchemy, Django's ORM is more consistent with the direct manipulation of SQL objects, exposing the simple direct mapping of data tables and Python-Class SQL objects.


$ django-admin.py startproject Demo
$ cd demo
$ python manage.py syncdb
creating Tables
... Creating table Django_admin_log
Creating table auth_permission
creating table Auth_group_permissions
Creating table Auth_group
Creating table auth_user_groups
creating table Auth_user_user_permissions
Creating table Auth_User
Creating table Django_content_type
Creating table django_session you
 
just Installed Django ' s auth system, which means you don ' t have any superusers defined.
Would to create one now? (yes/no): No
installing custom SQL ...
Installing Indexes
... Installed 0 object (s) from 0 fixture (s)
$ python manage.py shell

Because we weren't able to execute the Django code without first building a project, we created a Django demo project in the previous shell and then went into the Django Shell to test the ORM example we wrote.


# demo/models.py
>>> from django.db import models
>>>
>>>
>>> Class person (models. Model):
... name = models. TextField () ...
class Meta:
... app_label = ' demo '
...
>>>
>>> class address (models. Model):
... address = models. TextField () ... person
= models. ForeignKey (person) ...
class Meta:
... app_label = ' demo '
...

The code above declares 2 python classes, person, and address, each mapped to a database table. Before executing any database operation code, we need to create a table in the local SQLite database.

Python manage.py syncdb
creating Tables
... Creating table Demo_person
Creating table demo_address
Installing custom SQL
... Installing Indexes
... Installed 0 object (s) from 0 fixture (s)

To insert a person and an address to the database, we instantiate the corresponding object and invoke the Save () method of those objects.

>>> from Demo.models import person, address
>>> p = person (name= ' person ')
>>> p.save ()
>>> print "%r,%r"% (p.id, p.name)
1, ' person '
>>> a = Address (person=p, address= ' Addre SS ')
>>> a.save ()
>>> print "%r,%r"% (a.id, a.address)
1, ' address '

To get or retrieve person and address objects, we use the model class's magical object properties to get objects from the database.

>>> persons = Person.objects.filter (name= ' person ')
>>> persons
[]
>>> p = Persons[0]
>>> print "%r,%r"% (p.id, p.name)
1, u ' person '
>>> addresses = Address.objects.filter (person=p)
>>> addresses
[
 
<address>]
>>> a = Addresses[0]
>>> print "%r,%r"% (a.id, a.address)
1, u ' address '

PeeWee

PeeWee is a small, expression-type ORM. Compared to other Orm,peewee, the main focus is on minimalism, its API is simple, and its libraries are easy to use and understand.

Pip Install PeeWee
downloading/unpacking PeeWee
downloading Peewee-2.1.7.tar.gz (1.1MB): 1.1MB downloaded
Running setup.py egg_info for package PeeWee
 
Installing collected Packages:peewee
Running setup.py Install for PeeWee
changing mode of build/scripts-2.7/ pwiz.py from 644 to 755
 
changing mode of/users/xiaonuogantan/python2-workspace/bin/pwiz.py to 755
Successfully Installed PeeWee
Cleaning up ...

To create a database model map, we implemented a person class and an address class to map the corresponding database tables.


>>> from PeeWee Import Sqlitedatabase, Charfield, Foreignkeyfield, Model
>>>
>>> db = Sqlitedatabase (': Memory: ')
>>>
>>> class Person (Model):
... name = Charfield ()
... class Meta:
... database = db
...
>>>
>>> class Address (Model):
... address = Charfield () ... person
= Foreignkeyfield ( Person)
... class Meta:
... database = db
...
>>> person.create_table ()
>>> address.create_table ()

To insert objects into the database, we instantiate the objects and invoke their save () method. From the view's object creation point, PeeWee is similar to Django.

>>> p = person (name= "person")
>>> p.save ()
>>> a = Address (address= "address", person=p)
>>> a.save ()

To get or retrieve objects from the database, we select the objects of the class.


>>> person = Person.select (). WHERE (Person.name = = "Person"). Get ()
>>> person
 
>>> print '%r,%r '% (person.id, person.name)
1, u ' person '
>>> address = Address.select (). where ( Address.person = = person). Get ()
>>> print '%r,%r '% (address.id, address.address)
1, u ' address '

SQLAlchemy

SQLAlchemy is a Python programming language, an open source tool and a SQL ORM that is released under the MIT License. It was first published in February 2006, written by Michael Bayer. It provides "a well-known enterprise-class persistence model designed for efficient and high-performance database access, adapted as a complete suite of simple Python domain languages." It takes a data mapping pattern (like hibernate in Java) rather than an active record pattern (like Ruby on Rails's ORM).

SQLAlchemy's work unit makes it necessary to restrict all database operation code to a specific database session, in which the lifecycle of each object is controlled. Similar to other ORM, we begin by defining subclasses of Declarative_base () to map tables to Python classes.


>>> from SQLAlchemy import Column, String, Integer, ForeignKey
>>> from sqlalchemy.orm import Relat Ionship
>>> from sqlalchemy.ext.declarative import declarative_base
>>>
>>>
>>> Base = declarative_base ()
>>>
>>>
>>> class Person (base):
... __tablename__ = ' person '
... id = column (Integer, primary_key=true)
... name = column (String)
...
>>>
>>> class Address (Base):
... __tablename__ = ' address '
... id = Column (Integer, Primary_key=true)
... address = column (String)
... person_id = column (Integer, ForeignKey (person.id))
... person = relationship (person) ...

Before we write any database code, we need to create a database engine for the database session.

>>> from SQLAlchemy import create_engine
>>> engine = create_engine (' sqlite:///')

As soon as we create the database engine, we can continue to create a database session and create database tables for all previously defined person and address classes.

>>> from sqlalchemy.orm import Sessionmaker
>>> session = Sessionmaker ()
>>> Session.configure (bind=engine)
>>> Base.metadata.create_all (engine)

Now, the Session object object becomes the constructor of our unit of work, associating all subsequent database operation codes and objects with the database sessions built by invoking its __init__ () method.

>>> s = Session ()
>>> p = person (name= ' person ')
>>> S.add (p)
>>> a = Address (address= ' address ', person=p)
>>> S.add (a)

To get or retrieve objects in the database, we invoke the query () and filter () methods on the database session object.

>>> p = s.query. Filter (Person.name = = ' person '). One ()
>>> p
 
>>> print "%r,% R "% (P.id, p.name)
1, ' person '
>>> a = s.query (address). filter (Address.person = = p). One ()
> >> print "%r,%r"% (a.id, a.address)
1, ' address '

Please note that we have not submitted any changes to the database so far, so the new person and address objects are not actually stored in the database. Calling S.commit () will commit the changes, such as inserting a new person and a new address into the database.

>>> s.commit ()
>>> s.close ()

Comparison between Python ORM

For each Python ORM that is mentioned in the article, let's make a list of their pros and cons:
Sqlobject

Advantages:

    • With an understandable activerecord pattern.
    • A relatively small code base

Disadvantages:

    • Methods and class naming follow Java's little hump style
    • Database session isolation unit of work is not supported


Storm

Advantages:

    • Cool Lightweight API, short learning curve and long term maintainability
    • No special class constructors are required, and no necessary base classes

Disadvantages:

    • Forcing programmers to manually write DDL statements created by forms instead of automatically deriving from model classes
    • Storm contributors must make their contribution to the copyright canonical company


Django ' s ORM

Advantages:

    • Ease of use, short learning curve
    • Tightly set with Django and use the conventional method of using Django to manipulate the database

Disadvantages:

    • Difficult to handle complex queries, forcing developers to return to native SQL
    • Tight and Django integration, making it difficult to use outside the Django environment


PeeWee

Advantages:

    • Django API to make it easy to use
    • Lightweight implementation, easy to integrate with any web framework

Disadvantages:

    • Automated schema migration is not supported
    • Multiple queries are not straightforward to write


SQLAlchemy

Advantages:

    • Enterprise-class APIs that make code robust and adaptable
    • Flexible design makes it easy to write complex queries

Disadvantages:

    • Work unit concept not common
    • Heavyweight API, leading to long learning curve


Summary and Tips

Compared to other Orm, SQLAlchemy means that whenever you write SQLAlchemy code, you are focused on the cutting-edge concept of the work unit. The concept of DB session may initially be difficult to understand and use correctly, but later you will appreciate the extra complexity, which reduces the database bugs associated with unexpected timing submissions to 0. Processing multiple databases in SQLAlchemy is tricky because each DB session qualifies a database connection. However, this type of restriction is actually good because it forces you to rack your brains to interact with multiple databases, making database interaction code easy to debug.

In future articles, we will fully disclose the higher-order sqlalchemy use cases and truly appreciate the infinitely powerful APIs.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.