Heim >Backend-Entwicklung >Python-Tutorial >Ein super praktisches Python-Artefakt für die Verwendung von SQL!

Ein super praktisches Python-Artefakt für die Verwendung von SQL!

PHPz
PHPznach vorne
2023-04-18 16:19:031135Durchsuche

Ein super praktisches Python-Artefakt für die Verwendung von SQL!

Hintergrund

Tatsächlich habe ich am Anfang pymysql verwendet, aber festgestellt, dass die Wartung mühsam war und das Risiko einer Code-Injection bestand, also habe ich einfach das ORM-Framework direkt verwendet.

ORM ist Object Relational Mapper, der einfach als Zuordnung zwischen Datenbanktabellen und Python-Klassen verstanden werden kann. Durch den Betrieb von Python-Klassen können Sie die Datenbank indirekt bedienen.

Die bekannteren Python-ORM-Frameworks sind SQLAlchemy und Peewee. Ich werde hier keinen Vergleich anstellen, sondern nur die persönliche Verwendung von SQLAlchemy erläutern. Ich hoffe, dass es allen meinen Freunden hilfreich sein kann.

  • sqlalchemy-Version: 1.3.15
  • pymysql-Version: 0.9.3
  • MySQL-Version: 5.7

Initialisierungsarbeit

Im Allgemeinen fallen bei Verwendung eines ORM-Frameworks einige Initialisierungsarbeiten an, z. B. Datenbankverbindung, Definieren der grundlegenden Zuordnung usw.

Nehmen Sie MySQL als Beispiel. Um eine Datenbankverbindung herzustellen, müssen Sie nur die DSN-Zeichenfolge übergeben. Echo gibt an, ob die entsprechende SQL-Anweisung ausgegeben werden soll, was beim Debuggen hilfreich ist.

from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://$user:$password@$host:$port/$db?charset=utf8mb4', echo=True)

Persönliches Design

Für mich persönlich wird sich mein Projekt bei der Einführung des ORM-Frameworks auf das MVC-Muster für das folgende Design beziehen. Unter diesen speichert model einige Datenbankmodelle, d. h. Python-Klassen, die den einzelnen Modellen zugeordnet sind, d. Führt Datenbankoperationen aus, muss nur die Ebene model_op aufgerufen werden, und Sie müssen sich nicht um die Modellebene kümmern, um eine Entkopplung zu erreichen.

├── main.py
├── model
│ ├── __init__.py
│ ├── base_model.py
│ ├── ddl.sql
│ └── py_orm_model.py
└── model_op
├── __init__.py
└── py_orm_model_op.py

Mapping-Anweisung (Modelleinführung)

Zum Beispiel, wenn wir eine solche Testtabelle haben.

create table py_orm (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一id',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '名称',
`attr` JSON NOT NULL COMMENT '属性',
`ct` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`ut` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY(`id`)
)ENGINE=InnoDB COMMENT '测试表';

Im ORM-Framework ist das Mapping-Ergebnis die folgende Python-Klasse.

# py_orm_model.py
from .base_model import Base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text, JSON
class PyOrmModel(Base):
__tablename__ = 'py_orm'
id = Column(Integer, autoincrement=True, primary_key=True, comment='唯一id')
name = Column(String(255), nullable=False, default='', comment='名称')
attr = Column(JSON, nullable=False, comment='属性')
ct = Column(TIMESTAMP, nullable=False, server_default=text('CURRENT_TIMESTAMP'), comment='创建时间')
ut = Column(TIMESTAMP, nullable=False, server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), comment='更新时间')

Zunächst können wir sehen, dass PyOrmModel die Basisklasse erbt, eine von sqlalchemy bereitgestellte Basisklasse. Es wird einige Überprüfungen der von uns deklarierten Python-Klasse durchführen, und ich habe sie in base_model eingefügt.

# base_model.py
# 一般base_model做的都是一些初始化的工作
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:33306/orm_test?charset=utf8mb4", echo=False)

Zweitens muss jede Python-Klasse das Attribut __tablename__ enthalten, sonst kann die entsprechende Tabelle nicht gefunden werden.

Drittens gibt es zwei Möglichkeiten, eine Datentabelle manuell zu erstellen, solange es kein Problem mit Ihrer Python-Klassendefinition gibt über das ORM-Framework, z. B. unter.

# main.py
# 注意这里的导入路径,Base创建表时会寻找继承它的子类,如果路径不对,则无法创建成功
from sqlachlemy_lab import Base, engine
if __name__ == '__main__':
Base.metadata.create_all(engine)

Erstellungseffekt:

...
2020-04-04 10:12:53,974 INFO sqlalchemy.engine.base.Engine
CREATE TABLE py_orm (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '名称',
attr JSON NOT NULL COMMENT '属性',
ct TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
ut TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
)

Viertens zu Feldattributen:

1.Primärschlüssel und Autoinkrement sind leichter zu verstehen, sie sind der Primärschlüssel und die inkrementellen Attribute von MySQL.

2. Wenn es sich um einen int-Typ handelt, müssen Sie die Länge nicht angeben. Wenn es sich jedoch um einen varchar-Typ handelt, müssen Sie sie angeben.

3.nullable entspricht NULL und NOT NULL in MySQL

4. Über default und server_default: default stellt den Standardwert auf ORM-Framework-Ebene dar, d. h. wenn dem Feld beim Einfügen kein Wert zugewiesen wird, wird dies in unserer Definition der Fall sein Der Standardwert server_default stellt den Standardwert auf Datenbankebene dar, dh das Standardschlüsselwort in der DDL-Anweisung.

Einführung in die Sitzung

In der SQLAlchemy-Dokumentation wird erwähnt, dass Ergänzungen, Löschungen und Änderungen an der Datenbank durch Sitzungen durchgeführt werden.

>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=engine)
>>> session = Session()
>>> orm = PyOrmModel(id=1, name='test', attr={})
>>> session.add(orm)
>>> session.commit()
>>> session.close()

Wie oben können wir sehen, dass wir für jeden Vorgang die Sitzung erfassen, übermitteln und freigeben müssen. Dies ist zu redundant und mühsam, daher führen wir normalerweise eine Kapselung durch.

1. Verwenden Sie den Kontextmanager, um das abnormale Rollback und Schließen der Sitzung zu verwalten. Dieser Teil stimmt fast mit dem Artikel überein, auf den verwiesen wird.

# base_model.py
from contextlib import contextmanager
from sqlalchemy.orm import sessionmaker, scoped_session
def _get_session():
"""获取session"""
return scoped_session(sessionmaker(bind=engine, expire_on_commit=False))()
# 在这里对session进行统一管理,包括获取,提交,回滚和关闭
@contextmanager
def db_session(commit=True):
session = _get_session()
try:
yield session
if commit:
session.commit()
except Exception as e:
session.rollback()
raise e
finally:
if session:
session.close()

2. Fügen Sie PyOrmModel zwei Methoden für die Konvertierung zwischen Modell und Diktat hinzu.

class PyOrmModel(Base):
...
@staticmethod
def fields():
return ['id', 'name', 'attr']
@staticmethod
def to_json(model):
fields = PyOrmModel.fields()
json_data = {}
for field in fields:
json_data[field] = model.__getattribute__(field)
return json_data
@staticmethod
def from_json(data: dict):
fields = PyOrmModel.fields()
model = PyOrmModel()
for field in fields:
if field in data:
model.__setattr__(field, data[field])
return model

3. Anders als im Referenzartikel habe ich die Sitzung direkt aufgerufen, sodass der Aufrufer nicht auf die Modellebene achten muss und die Kopplung reduziert wird.

# py_orm_model_op.py
from sqlachlemy_lab.model import db_session
from sqlachlemy_lab.model import PyOrmModel
class PyOrmModelOp:
def __init__(self):
pass
@staticmethod
def save_data(data: dict):
with db_session() as session:
model = PyOrmModel.from_json(data)
session.add(model)
# 查询操作,不需要commit
@staticmethod
def query_data(pid: int):
data_list = []
with db_session(commit=False) as session:
data = session.query(PyOrmModel).filter(PyOrmModel.id == pid)
for d in data:
data_list.append(PyOrmModel.to_json(d))
return data_list

4. Anrufer:

# main.py
from sqlachlemy_lab.model_op import PyOrmModelOp
if __name__ == '__main__':
PyOrmModelOp.save_data({'id': 1, 'name': 'test', 'attr': {}})

Das obige ist der detaillierte Inhalt vonEin super praktisches Python-Artefakt für die Verwendung von SQL!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:51cto.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen