12/08/2018, 13:02

Giới thiệu sQLAlchemy trong python (part 2)

Tổng quan về ORM trong Python Giống như nhiều ngôn ngữ khác, Python cũng có nhiều thư viện ORM ngoài Sqlalchemy. Trong bài viết này, chúng ta sẽ đi tìm hiểu một số thư viện ORM phổ biến, để có thể hiểu vào rõ ràng hơn bức tranh lớn về các thư viện O R M trong python. Trong bài viết sẽ sử dụng ...

Tổng quan về ORM trong Python

  • Giống như nhiều ngôn ngữ khác, Python cũng có nhiều thư viện ORM ngoài Sqlalchemy. Trong bài viết này, chúng ta sẽ đi tìm hiểu một số thư viện ORM phổ biến, để có thể hiểu vào rõ ràng hơn bức tranh lớn về các thư viện O R M trong python. Trong bài viết sẽ sử dụng một database đơn giản có hai bảng: person và address, chúng ta sẽ sử dụng nó với mỗi O R M để hiểu rõ hơn ,những điểm mạnh , điểm yếu của mỗi O R M

SQLObject

  • SQLObject là một O R M trong Python, nó có chức năng chính là "map" một record trong cơ sở dữ liệu SQL và đối tượng Python.
  • Trong SQLObject, dữ liệu được "map" theo cách cũng giống như trong Sqlalchemy: một bảng được "map" với một class , một record được "map" với một object, một column được "map" với một thuộc tính(attribute) của object. Do đó nó làm cho việc truy vấn các đối tượng Python trừu tượng hơn dựa trên những câu truy vấn SQL trong cơ sở dữ liệu.
  • Chúng ta sẽ tạo ra 2 bảng Person và Address như đã nói ở trên, thực hiện:

Cài đặt sqlObject

    pip install sqlobject

Trong python console

    from sqlobject import StringCol, SQLObject, ForeignKey, sqlhub, connectionForURI
    sqlhub.processConnection = connectionForURI('sqlite:/:memory:')

    class Person(SQLObject):
        name = StringCol()

    class Address(SQLObject):
        address = StringCol()
        person = ForeignKey('Person')

    Person.createTable()
    Address.createTable()

Tạo ra dữ liệu cho database( trong Python consonle)

        p = Person(name='person')
        a = Address(address='address', person=p)

Ta có thể thực hiện một số những truy vấn đơn giản như(trong Python console)

    # Lấy danh sách các đối tượng Person có thuộc tính 'name' là 'person':
        persons = Person.select(Person.q.name == 'person')
    # Kiểm tra xem đối tượng p đã tạo ra ở trên có tồn tại hay không?
        list(persons)
        p1 = persons[0]
        p1 = p
    # Kết quản nhận được là True
    # Lấy ra địa chỉ của đối tượng Person p:
        addresses = Address.select(Address.q.person == p1)
    # Kiểm tra xem kết quả dữ liệu trả về:
        list(addresses)
        address = addresses[0]
        address = a
    # Kết quả trả về True

Storm

  • Storm là môt Python O R M , cho phép "map" một đối tượng Python tới một hay nhiều bảng trong cơ sở dữ liệu. Điều này tạo điều kiện cho developer tạo ra những câu truy vấn phức tạp lấy dữ liệu từ nhiều bảng khác nhau khi lấy thông tin của một đối tượng Python.
  • Nó được phát triển tích hợp trong Python tại Canonical Ltd, công ty đứng sau Unbuntu, nơi đã phát triển Launchpad và Landscape , những ứng dụng này đã được ra mắt năm 2007, và nó là những ứng dụng free
  • Cũng giống như SQLAlchemy và SQLObject, Storm cũng "map" một bảng với một class, một record với một object và một column với một thuộc tính. Tuy nhiên , so sánh với SQLAlchemy , Một bảng của Storm không bắt buộc phải là lớp con (subclasses) của một lớp cha( superclasses) nào đó trong framework-specific, tuy nhiên trong SQLAlchemy, mọi bảng đều là lớp con(subclasses) của sqlalchemy.ext.declarative.declarative_bas. Trong SQLObject, mọi bảng đều là lớp con(subclasses) của sql.SQLObject
  • Giống như SQLAlchemy, Storm Store cũng lưu trữ các hành động của đối tượng như các backend database, các phép toán được cached trong memory và được commit vào database một lần duy nhất khi phương thức commit được gọi đến. Nó cũng khá giống với đối tượng session của Sqlalchemy. Các phiên bản khác nhau của Storm có thể download trực tiếp theo link: Download Storm!.
  • Khi đó 2 bảng Person và Address có thể định nghĩa như sau:
    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)
  • Đoạn mã trên tạo một cơ sỡ dữ liệu sqlite trong bộ memory, và một đối tượng store( đối tượng store tương tự với đối tượng session của SqlAlchemy).
   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'
   print person

   print "%r, %r" % (person.id, person.name)
    None, u'person' # Notice that person.id is None since the Person instance is not attached to a valid database store yet.
   store.add(person)

   print "%r, %r" % (person.id, person.name)
    None, u'person' # Since the store hasn't flushed the Person instance into 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 an 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)
  • Để get đối tượng person và địa chỉ(address), ta có thể làm như sau:
   person = store.find(Person, Person.name == u'person').one()
   print "%r, %r" % (person.id, person.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.address)
    1, u'address'

Django O R M

  • Django là một trong những framework dùng để phát triển các ứng dụng phổ biến trong ngôn ngữ Python. Django O R M được phát triển sát sao với framwork Django. Sau khi được cho ra mắt, Django ngày càng trở lên phổ biến, do tính dễ sử dụng , và rất thuận tiện để phát triển nhứng ứng dụng web. Nó được cho ra mắt dưới sự cấp phép BSD license vào tháng 7 2005. Django O R M được tích hợp sẵn vào framework Django, tuy nhiên nó không phải là bắt buộc, người sử dụng framework Django cũng vẫn có thể sử dụng các O R M khác để phát triển những ứng dụng của mình( sử dụng SQLalchemy chẳng hạn).
  • Django là một trong những Python web frameworks phổ biến, nó có một O R M tận tâm, so sánh với SQLAlchemy, Django O R M nhắm đến các đối tượng SQL và thực hiện việc map đối tượng trong dabase và các đối tượng Python.

Ví dụ

    $ 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 you like to create one now? (yes/no): no
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)
    $ python manage.py shell
  • Đoạn code trên xây dựng một project có tên là 'demo', khi tạo mới một project, Django sẽ có một số tùy chọn trong việc tạo super user, super user mang những ý nghĩa riêng như chúng ta định nghĩa một super user thông thường.
  • Quay lại với bài toán của chúng ta, chúng ta sẽ xây dựng database với hai bảng Person và Address như sau:
# 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'
  • Tạo đối tượng và truy vấn đơn giản như sau:
   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='address')
   a.save()
   print "%r, %r" % (a.id, a.address)
    1, 'address'
   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'

SQLAlchemy

  • SQLAlchemy là một công cụ mã nguồn mở của SQL và O R M , được phát hành theo giấy phép MIT. Nó được phát hành ban đầu vào tháng Hai năm 2006, và được viết bởi Michael Bayer. Nó cung cấp đầy đủ các phương thức, ở level cao, đảm bảo cho việc truy cập cơ sở dữ liệu hiệu suất cao, là một chuyển thể đơn giản của Pythonic language. , nó hoạt đông theo data mapper pattern ( như Hibernate trong Java), chứ không phải là record pattern như trong Ruby and Rails
  • Database sẽ được định nghĩa như sau :
   from sqlalchemy import Column, String, Integer, ForeignKey
   from sqlalchemy.orm import relationship
   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)
  • Việc tạo đối tượng và truy vấn đơn giản trong bài toán ví dụ sẽ như sau:
   s = session()
   p = Person(name='person')
   s.add(p)
   a = Address(address='address', person=p)
   s.add(a)

   p = s.query(Person).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'

   s.commit()
   s.close()

Tổng kết về điểm mạnh, điểm yếu của các O R M

SQLObject

- **Điểm mạnh** :
    + Hoạt động dựa trên ActiveRecord Pattern, đơn giản dễ hiểu.
    + Một codebase tương đối nhỏ
- **Điểm yếu**:
    + Việc đặt tên các phương thức và class phải tuân theo chuẩn Java Cammel
    + Không hỗ trợ session, để phân các công việc thạnh những unit nhỏ

Storm

- **Điểm mạnh** :
    + Một API, dễ dàng cho việc học và maintain
    + Không cần những hàm khởi tạo đặc biệt, và không cần dựa trên bất kỳ một base class nào.
- **Điểm yếu**:
    + Phải ghi rõ Storm được sử dụng từ Canonical Ltd.
    + Bắt buộc các lập tình viên phải viết các câu lệnh D D L một cách thủ công thay vì việc tự động bắt từ model class

Django O R M

- **Điểm mạnh** :
    + Đơn giản để sử dụng, thời gian học tập ngắn
    + Tích hợp chặt chẽ với Django, trở thành một chuẩn để tương tác với database trong Django
- **Điểm yếu**:
    + Thực hiện các truy vấn phức tạp là khó khăn, buộc lập trình trình viên phải truyền vào các câu lệnh SQL nguyên bản.
    + Việc tích hợp chặt chẽ với Django cũng gây ra việc khó khăn trong việc sử dụng O R M này ngoài khuôn khổ của frame Django

SQLAlchemy

- **Ưu điểm**:
    + Giúp công việc lập trình trở lên đơn giản, mạnh mẽ hơn
    + Thiết kế linh hoạt, đơn giản để tạo ra các câu truy vấn phức tạp
- **Nhược điểm**:
    + Khái niệm Unit-of -work không phổ biến
    + Một API nặng; dẫn đến việc học tập dài
0