Giới thiệu sqlalchemy trong python(part 1)

Python's SQLAlchemy và Object-Relational Mapping

Một nhiệm vụ phổ biến khi bắt đầu xây dựng một web service bất kỳ là làm sao để xây dựng một cơ sở dữ liệu chắc chắn, bền vững. Trong quá khứ, lập trình viên sẽ phải viết những câu lệnh SQL, thông qua chúng, để thiết database hay lấy dữ liệu từ database. Ngày nay, lập trình viên có thể sử dụng object-relational mapping( ORM) thay vì các câu lệnh SQL phức tạp, và khó khăn trong việc bảo trì, đọc hiểu và chỉnh sửa.

ORM là một công nghệ lập trình, cho phép chuyển đổi (convert) từ những data trong database với những đối tượng trong các ngôn ngữ lập trình hướng đối tượng. Thông thường, những ngôn ngữ hướng đối tượng như python tồn tại những kiểu không thể thể hiện bằng các kiểu nguyên thủy(giống như là integer, string) .

Ví dụ, Một người có thể có các địa chỉ nhà ở khác nhau, như địa chỉ thường trú chỗ này , chỗ kia, có một, vài số điện thoại hay dùng, Một địa chỉ thì phải lưu trữ mã bưu điện của tỉnh/thành phố đó, hay lưu trữ tên đường, số nhà.v.v. Điều này thể hiện trong ngôn ngữ hướng đối tượng như sau:

Một Person object có thể có một danh sách các Address object, và một danh sách các PhoneNumber object. Một Address object có một PostCode object., một StreetName object và một StreetNumber object.

Mặc dù một object đơn giản như PostCode và StreetName có thể biểu diễn bằng các string, nhưng những object phức tạp hơn, giống như Address object hay Person, không thể chỉ sử dụng những kiểu nguyên thủy như String, Integer để thể hiện. Thêm vào đó, những đối tượng phức tạp có thể bao gồm các thể hiện của một class, hoặc các phương thức trong class không thể sử dụng 1 kiểu cho tất cả các trường hợp.

Để quản lý những đối tượng phức tạp, con người đã phát triển một lớp hệ thống mới , gọi là ORM. Ở ví dụ trước của chúng ta, ORM có thể xây dựng với các thành phần: một class Person, một class Address , một class PhoneNumber và một class mapper để thực hiện việc map một python class với một bảng trong database. Thay vì phải viết những code SQL tẻ nhạt, một ORM có thể mang đển cho bạn những tùy chọn có thể sử dụng trong khi lập trình những logic của hệ thống SQLAlchemyPersonAddress.png

Trong thiết kế này, chúng ta có 2 bảng person và address và address.person_id là khóa ngoài của person với bảng address. Giờ chúng ta sẽ viết code một cơ sở dữ liệu tướng ứng trong file sqlite_ex.py


    import sqlite3
    conn = sqlite3.connect('example.db')

    c = conn.cursor()
    c.execute('''
              CREATE TABLE person
              (id INTEGER PRIMARY KEY ASC, name varchar(250) NOT NULL)
              ''')
    c.execute('''
              CREATE TABLE address
              (id INTEGER PRIMARY KEY ASC, street_name varchar(250), street_number varchar(250),
               post_code varchar(250) NOT NULL, person_id INTEGER NOT NULL,
               FOREIGN KEY(person_id) REFERENCES person(id))
              ''')

    c.execute('''
              INSERT INTO person VALUES(1, 'pythoncentral')
              ''')
    c.execute('''
              INSERT INTO address VALUES(1, 'python road', '1', '00000', 1)
              ''')

    conn.commit()
    conn.close()

Chú ý rằng chúng ta sẽ chèn một record vào mỗi bảng. thực hiện câu lệnh sau

    $ python sqlite_ex.py

Giờ chúng ta có thể thự hiện việc truy vấn trong cơ sở dữ liệu example.db để lấy những bản ghi. Viết một code sau trong file sqlite_q.py

    import sqlite3
    conn = sqlite3.connect('example.db')

    c = conn.cursor()
    c.execute('SELECT * FROM person')
    print c.fetchall()
    c.execute('SELECT * FROM address')
    print c.fetchall()
    conn.close()

và thực hiện câu lệnh sau:

    $ python sqlite_q.py
    [(1, u'pythoncentral')]
    [(1, u'python road', u'1', u'00000', 1)]

Ở ví dụ trước, chúng ta sử dụng 1 sqlite3 conecttion để commit sự thay đổi trong database và một sqlite3 cursor để thực hiện một câu lệnh sql. Mục đích của những cậu lệnh này là CRUD(create, read, update, delete) dữ liệu trong database.

Mặc dù câu lệnh SQL đã thực thi, nhưng nó không dễ dàng đọc hiểu, hay thay đổi. Trong giai đoạn tiếp theo , chúng ta sẽ sử dụng những khai báo SQLAlchemy để thực hiện việc map mỗi Person và Address với những python class.

Python's SQLAlchemy và Declarative

  • ở đây có 3 thành phần quan trọng khi viết SQLalchemy code:
    • Một bảng(table) trong cơ sở dữ liệu
    • Một mapper để map python class và một bảng trong database
    • Một class object định nghĩa những thành phần của đối tượng
  • Thay vì viết code cho table, mapper và class object ở những nơi khác nhau, SQLALchemy declarative đồng ý cho việc table, mapper, và class object định nghĩa trong 1 lớp
  • Dưới đây là khai báo các định nghĩa giống như các bảng được định nghĩa trong file sqlite_ex.py

    import os
    import sys
    from sqlalchemy import Column, ForeignKey, Integer, String
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import relationship
    from sqlalchemy import create_engine

    Base = declarative_base()

    class Person(Base):
        __tablename__ = 'person'
        # Here we define columns for the table person
        # Notice that each column is also a normal Python instance attribute.
        id = Column(Integer, primary_key=True)
        name = Column(String(250), nullable=False)

    class Address(Base):
        __tablename__ = 'address'
        # Here we define columns for the table address.
        # Notice that each column is also a normal Python instance attribute.
        id = Column(Integer, primary_key=True)
        street_name = Column(String(250))
        street_number = Column(String(250))
        post_code = Column(String(250), nullable=False)
        person_id = Column(Integer, ForeignKey('person.id'))
        person = relationship(Person)

    # Create an engine that stores data in the local directory's
    # sqlalchemy_example.db file.
    engine = create_engine('sqlite:///sqlalchemy_example.db')

    # Create all tables in the engine. This is equivalent to "Create Table"
    # statements in raw SQL.
    Base.metadata.create_all(engine)

Lưu code trên với tên là sqlalchemy_insert.py và thực thi file đó bằng câu lệnh

    python sqlalchemy_insert.py

Giờ đấy chúng ta có một đối tượng Person, 1 đối tượng Address được lưu trữ trong database. Bây giờ chúng ta sẽ thực hiện việc truy vấn trong cơ sở dữ liệu sử dụng những lớp đã định nghĩa trong file sqlalchemy_declarative.py. Thực hiện python console và thực hiện lần lượt những câu lệnh sau:

        from sqlalchemy_declarative import Person, Base, Address
        from sqlalchemy import create_engine
        engine = create_engine('sqlite:///sqlalchemy_example.db')
        Base.metadata.bind = engine
        from sqlalchemy.orm import sessionmaker
        DBSession = sessionmaker()
        DBSession.bind = engine
        session = DBSession()
        #Make a query to find all Persons in the database
        session.query(Person).all()
        [<sqlalchemy_declarative.Person object at 0x2ee3a10>]

        # Return the first Person from all Persons in the database
        person = session.query(Person).first()
        person.name
        u'new person'

        # Find all Address whose person field is pointing to the person object
        session.query(Address).filter(Address.person == person).all()
        [<sqlalchemy_declarative.Address object at 0x2ee3cd0>]

        # Retrieve one Address whose person field is point to the person object
        session.query(Address).filter(Address.person == person).one()
        <sqlalchemy_declarative.Address object at 0x2ee3cd0>
        address = session.query(Address).filter(Address.person == person).one()
        address.post_code
        u'00000'

Tổng kết

Trong bài này, chúng ta đã học làm sao để có xây dựng một database sử dụng SQLAlchemy's declaratives. So sánh nó với việc viết những câu lệnh SQL truyền thống trong sqlite3, SQLAlchemy code hướng đối tượng hơn, dễ dàng để đọc và duy trì hơn. Thêm vào đó, chúng ta có thể dễ dàng thực hiện việc tạo mới, sửa, xóa các đối tượng SQLAlchemy giống như những đối tượng python thông thường

Nguồn tham khảo

  • Bài viết được viết được theo tài liệu về sqlalchemy của tác giả Xiaonuo Gantan.
  • Những phần tiếp theo trong tutorial sử dụng sqlalchemy trong python cũng sẽ bám sát theo những tài liệu và bài viết của tác giả Xiaonuo Gantan.