Pyramid 使用SQLAlchemy

2023-03-30 17:46 更新

在本章中,我們將學(xué)習(xí)如何使用關(guān)系型數(shù)據(jù)庫作為Pyramid網(wǎng)絡(luò)應(yīng)用程序的后端。Python可以使用相應(yīng)的DB-API兼容的連接器模塊或驅(qū)動(dòng)程序與幾乎所有的關(guān)系型數(shù)據(jù)庫進(jìn)行交互。然而,我們將使用 SQLAlchemy 庫作為Python代碼和數(shù)據(jù)庫之間的接口(我們將使用SQLite數(shù)據(jù)庫,因?yàn)镻ython對它有內(nèi)置的支持)。SQLAlchemy是一個(gè)流行的SQL工具箱和對象關(guān)系映射器。

對象關(guān)系映射是一種編程技術(shù),用于在面向?qū)ο缶幊陶Z言中不兼容的類型系統(tǒng)之間轉(zhuǎn)換數(shù)據(jù)。通常,在Python這樣的面向?qū)ο笳Z言中使用的類型系統(tǒng)包含非標(biāo)量類型。然而,大多數(shù)數(shù)據(jù)庫產(chǎn)品如Oracle、MySQL等的數(shù)據(jù)類型是原始類型,如整數(shù)和字符串。

在ORM系統(tǒng)中,每個(gè)類都映射到底層數(shù)據(jù)庫中的一個(gè)表。ORM不需要自己編寫繁瑣的數(shù)據(jù)庫接口代碼,而是為你解決這些問題,而你可以專注于系統(tǒng)的邏輯編程。

為了使用SQLALchemy,我們需要首先使用PIP安裝程序來安裝該庫。

pip install sqlalchemy

SQLAlchemy被設(shè)計(jì)為與為特定數(shù)據(jù)庫建立的DBAPI實(shí)現(xiàn)一起運(yùn)行。它使用方言系統(tǒng)來與各種類型的DBAPI實(shí)現(xiàn)和數(shù)據(jù)庫進(jìn)行通信。所有的方言都需要安裝一個(gè)合適的DBAPI驅(qū)動(dòng)程序。

以下是包括的方言 –

  • Firebird
  • Microsoft SQL Server
  • MySQL
  • Oracle
  • PostgreSQL
  • SQLite
  • Sybase

數(shù)據(jù)庫引擎

由于我們要使用SQLite數(shù)據(jù)庫,我們需要為我們的數(shù)據(jù)庫創(chuàng)建一個(gè)名為 test.db 的數(shù)據(jù)庫引擎 。 從 sqlalchemy 模塊導(dǎo)入 create_engine() 函數(shù)。

from sqlalchemy import create_engine
from sqlalchemy.dialects.sqlite import *
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args = {"check_same_thread": False})

為了與數(shù)據(jù)庫進(jìn)行交互,我們需要獲得其句柄。會(huì)話對象是數(shù)據(jù)庫的句柄。會(huì)話類是用 sessionmaker() 定義的,這是一個(gè)可配置的會(huì)話工廠方法,它被綁定到引擎對象上。

from sqlalchemy.orm import sessionmaker, Session
session = sessionmaker(autocommit=False, autoflush=False, bind=engine)

接下來,我們需要一個(gè)聲明性的基類,在聲明性系統(tǒng)中存儲一個(gè)類和映射表的目錄。

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

模型類

Students , Base 的一個(gè)子類,被映射到數(shù)據(jù)庫中的一個(gè) 學(xué)生 表。 學(xué)生 類中的屬性與目標(biāo)表中的列的數(shù)據(jù)類型相對應(yīng)。請注意,id屬性與書表中的主鍵相對應(yīng)。

class Students(Base):
   __tablename__ = 'student'
   id = Column(Integer, primary_key=True, nullable=False)
   name = Column(String(63), unique=True)
   marks = Column(Integer)
Base.metadata.create_all(bind=engine)

create_all() 方法在數(shù)據(jù)庫中創(chuàng)建相應(yīng)的表。可以通過使用SQLite Visual工具(如 SQLiteStudio )來確認(rèn)。

Python Pyramid - 使用SQLAlchemy

現(xiàn)在我們將定義視圖函數(shù),用于對上述數(shù)據(jù)庫中的學(xué)生表進(jìn)行CRUD操作(即添加、顯示、修改和刪除行)。

添加一個(gè)新的學(xué)生記錄

首先,我們將創(chuàng)建一個(gè)HTML表單模板,供用戶輸入學(xué)生數(shù)據(jù),并定義一個(gè)視圖來渲染該模板。下面是 myform.html 模板

例子

<html>
<body>
   <form method="POST" action="http://localhost:6543/add">
   <p>Student Id: <input type="text" name="id"/> </p>
   <p>student Name: <input type="text" name="name"/> </p>
   <p>Percentage: <input type="text" name="percent"/> </p>
   <p><input type="submit" value="Submit"> </p>
</body>
</html>

在Pyramid應(yīng)用程序代碼中,定義index()視圖函數(shù)來呈現(xiàn)上述表單。

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config

@view_config(route_name='index', renderer='templates/myform.html')
def index(request):
   return {}

在應(yīng)用程序配置中,用”/new “模式為該視圖注冊路由,即

if __name__ == '__main__':
   with Configurator() as config:
      config.include('pyramid_jinja2')
      config.add_jinja2_renderer(".html")
      config.add_route('index', '/new')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

由于上述模板中的HTML表單是通過POST動(dòng)作提交給 /add URL的,我們需要將這個(gè)URL映射到add route,并注冊add()視圖,將表單數(shù)據(jù)解析成一個(gè)學(xué)生類的對象。這個(gè)對象被添加到數(shù)據(jù)庫會(huì)話中,并通過調(diào)用commit()方法最終完成操作。

@view_config(route_name='add', request_method='POST')
def add(request):
   id=request.POST['id']
   name=request.POST['name']
   percent=int(request.POST['percent'])
   student=Students(id=id, name=name, percent=percent)
   session.add(student)
   session.commit()
   return HTTPFound(location='http://localhost:6543/')

確保在配置中添加添加路由,映射到/添加URL模式。

config.add_route('add','/add')

輸出

如果我們啟動(dòng)服務(wù)器并在瀏覽器中打開 http://localhost:6543/new ,輸入表單將顯示如下—-。

Python Pyramid - 使用SQLAlchemy

填寫表格并按下 “提交 “按鈕。add()視圖將被調(diào)用,一條新記錄將被添加到學(xué)生表中。重復(fù)這個(gè)過程幾次以添加一些記錄。Here is a sample data ?

Python Pyramid - 使用SQLAlchemy

顯示所有記錄的列表

學(xué)生模型的所有對象(對應(yīng)于學(xué)生表中的行)都是通過查詢該模型獲得的。

rows = session.query(Students).all()

每一行都被轉(zhuǎn)換為一個(gè)dict對象,所有的dict對象都被追加到一個(gè)列表中,并作為一個(gè)上下文返回到list.html模板中,以HTML模板的形式顯示。這個(gè)過程是由showall()視圖函數(shù)執(zhí)行的,與list route相關(guān)。

@view_config(route_name='list', renderer='templates/marklist.html')
def showall(request):
   rows = session.query(Students).all()
   students=[]
   for row in rows:
      students.append({"id":row.id, "name":row.name, "percent":row.percent})
   return{'students':students}

例子

marklist.html 模板將學(xué)生名單渲染成一個(gè)HTML表格。它的HTML/jinja2腳本如下

<html>
<body>
<table border=1>
   <thead> 
      <tr>
         <th>Student ID</th>
         <th>Student Name</th>
         <th>percentage</th>
         <th>Edit</th>
         <th>Delete</th>
      </tr> 
   </thead>
   <tbody>
      {% for Student in students %}
         <tr>
         <td>{{ Student.id }}</td> <td>{{ Student.name }}</td>
         <td>{{ Student.percent }}</td>
         <td><a href="/show/{{ Student.id }}">edit</a></td>
         <td><a href="/delete/{{ Student.id }}">delete</a></td>
         </tr>
      {% endfor %}
   </tbody>
</table>
<h3><a href="http://localhost:6543/new" rel="external nofollow" target="_blank" >Add new</a></h3>
   </body>
</html>

在配置中添加列表路由,并以’/’URL注冊。

config.add_route('list', '/')

輸出

啟動(dòng)服務(wù)器后在瀏覽器中打開 http://localhost:6543/ 。將顯示學(xué)生表中的現(xiàn)有記錄列表。

Python Pyramid - 使用SQLAlchemy

注意最后兩列中的超鏈接。例如,”id=1 “前面的 “編輯 “鏈接指向 http://localhost:6543/show/1 。這些鏈接是為了執(zhí)行更新和刪除操作。

更新現(xiàn)有記錄

在/show/1的URL中,有一個(gè)尾部的路徑參數(shù)。它被映射到配置中的’show’路線。

config.add_route('show', '/show/{id}')

這個(gè)路由調(diào)用show()函數(shù)。它獲取與給定id參數(shù)相對應(yīng)的記錄,將其內(nèi)容填充到HTML表單中,并讓用戶更新姓名和/或百分比字段的值。

@view_config(route_name='show', renderer='templates/showform.html')
def show(request):
   id=request.matchdict['id']
   row = session.query(Students).filter(Students.id == id).first()
   student={'id':row.id, 'name':row.name, 'percent':row.percent}
   return {'student':student}

例子

showform.html模板的HTML/jinja2代碼如下。

<html>
<body>
   <form method="POST" action="http://localhost:6543/update">
   <p>Student Id: <input type="text" name="id" value="{{ student.id }} " readonly/> </p>
   <p>student Name: <input type="text" name="name" value="{{ student.name }}"/> </p>
   <p>Percentage: <input type="text" name="percent" value="{{ student.percent }}"/> </p>
   <p><input type="submit" value="Submit"> </p>
</body>
</html>

輸出

讓我們更新id=3的記錄。點(diǎn)擊相應(yīng)的編輯鏈接,導(dǎo)航到 http://localhost:6543/show/3

Python Pyramid - 使用SQLAlchemy

改變標(biāo)記文本字段中的值并按提交。表格被重定向到/update URL,它調(diào)用update()視圖。它獲取提交的數(shù)據(jù)并更新相應(yīng)的對象,因此學(xué)生表中的基本行也被更新。

@view_config(route_name='update', request_method='POST')
def update(request):
   id=int(request.POST['id'])
   student = session.query(Students).filter(Students.id == id).first()
   student.percent=int(request.POST['percent'])
   session.commit()
   return HTTPFound(location='http://localhost:6543/')

返回語句將瀏覽器重定向到’/’URL,它指向list()函數(shù)并顯示更新的標(biāo)記列表。

Python Pyramid - 使用SQLAlchemy

確保在運(yùn)行前將更新路線添加到配置中。

config.add_route('update', '/update')

刪除一條記錄

要?jiǎng)h除標(biāo)記表中某一行對應(yīng)的記錄,請按照最后一列中的刪除鏈接。例如,點(diǎn)擊第三行的Delete會(huì)發(fā)出 http://localhost:6543/delete/3 URL,并調(diào)用以下視圖功能:

@view_config(route_name='delete', renderer='templates/deleted.html')
def delete(request):
   id=request.matchdict['id']
   row = session.query(Students).filter(Students.id == id).delete()
   return {'message':'Redcord has been deleted'}

例子

與從URL解析出的路徑參數(shù)相對應(yīng)的對象被刪除,相應(yīng)的信息由以下模板呈現(xiàn) - deleted.html - 。

<html>
<body>
   <h3>{{ message}}</h3>
   <br><br>
   <a href="http://localhost:6543/" rel="external nofollow" target="_blank" >Click here to refresh the mark list</a>
</body>
</html>

很明顯,刪除路徑必須被添加到應(yīng)用程序配置注冊表中。

config.add_route('delete', '/delete/{id}')

輸出

記錄刪除動(dòng)作的結(jié)果如下所示

Python Pyramid - 使用SQLAlchemy

采取以下步驟來執(zhí)行上述解釋的活動(dòng)

  • 在Pyramid虛擬環(huán)境中創(chuàng)建一個(gè)名為 testapp 的文件夾。
  • 在 testapp 中,創(chuàng)建 templates 文件夾。
  • 在testapp中創(chuàng)建一個(gè)空白的 __init__.py ,使其成為一個(gè)包。
  • 將marklist.html、myform.html、showform.html和delete.html文件放在 “testapp/templates “文件夾中。這些文件的代碼已經(jīng)在上面給出。
  • 在 testapp 中保存以下代碼為 models.py。
from sqlalchemy.dialects.sqlite import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import Session
from sqlalchemy import Column, Integer, String
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"

Base = declarative_base()

class Students(Base):
      __tablename__ = 'student'
   id = Column(Integer, primary_key=True, nullable=False)
   name = Column(String(63), unique=True)
   percent = Column(Integer)

def getsession():
   engine = create_engine(
      SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
   )
   Base.metadata.create_all(bind=engine)
   Session = sessionmaker(bind = engine)
   session = Session()
   return session
  • 在 testapp 文件夾中保存以下代碼為 views.py 。
from pyramid.response import Response
from pyramid.view import view_config
from pyramid.httpexceptions import HTTPFound
from models import Students
from main import session

@view_config(route_name='list', renderer='templates/marklist.html')
def showall(request):
   rows = session.query(Students).all()
   students=[]
   for row in rows:
      students.append({"id":row.id, "name":row.name, "percent":row.percent})
      return{'students':students}

@view_config(route_name='index', renderer='templates/myform.html')
def index(request):
   return {}

@view_config(route_name='add', request_method='POST')
def add(request):
   id=request.POST['id']
   name=request.POST['name']
   percent=int(request.POST['percent'])
   student=Students(id=id, name=name, percent=percent)
   session.add(student)
   session.commit()
   return HTTPFound(location='http://localhost:6543/')

@view_config(route_name='update', request_method='POST')
def update(request):
   id=int(request.POST['id'])
   student = session.query(Students).filter(Students.id == id).first()
   student.percent=int(request.POST['percent'])
   session.commit()
   return HTTPFound(location='http://localhost:6543/')

@view_config(route_name='show', renderer='templates/showform.html')
def show(request):
   id=request.matchdict['id']
   row = session.query(Students).filter(Students.id == id).first()
   student={'id':row.id, 'name':row.name, 'percent':row.percent}
   return {'student':student}

@view_config(route_name='delete', renderer='templates/deleted.html')
def delete(request):
   id=request.matchdict['id']
   row = session.query(Students).filter(Students.id == id).delete()
   return {'message':'Redcord has been deleted'}
  • 將以下代碼保存為testapp文件夾中的main.py。
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from models import getsession
session=getsession()

if __name__ == '__main__':
   with Configurator() as config:
      config.include('pyramid_jinja2')
      config.add_jinja2_renderer(".html")
      config.add_route('list', '/')
      config.add_route('index', '/new')
      config.add_route('add','/add')
      config.add_route('show', '/show/{id}')
      config.add_route('update', '/update')
      config.add_route('delete', '/delete/{id}')
      config.scan('testapp')
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()    
  • 在命令提示符下運(yùn)行 main.py 。
Python main.py
  • 在瀏覽器窗口中使用 http://localhost:6543/ URL。一個(gè)只有標(biāo)題而沒有記錄的表格將被顯示。
  • 按照表格下方的 “添加新 “鏈接來添加記錄。
  • 點(diǎn)擊表格中的 “編輯 “鏈接來更新記錄。
  • 點(diǎn)擊表格中的 “刪除 “鏈接,刪除選定的記錄。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號