En fait, j'ai utilisé pymysql au début, mais j'ai trouvé que la maintenance était gênante et qu'il y avait un risque d'injection de code, j'ai donc simplement utilisé directement le framework ORM.
ORM est Object Relational Mapper, qui peut être simplement compris comme le mappage entre les tables de base de données et les classes Python. En exploitant des classes Python, vous pouvez indirectement exploiter la base de données.
Les frameworks Python ORM les plus connus sont SQLAlchemy et Peewee. Je ne ferai pas de comparaison ici, mais expliquerai simplement une utilisation personnelle de SQLAlchemy. J'espère que cela pourra être utile à tous mes amis.
Généralement, lors de l'utilisation d'un framework ORM, il y aura un travail d'initialisation, tel que la connexion à une base de données, définir une cartographie de base, etc.
Prenons MySQL comme exemple. Pour créer une connexion à une base de données, il vous suffit de transmettre la chaîne DSN. Echo indique s'il faut afficher l'instruction SQL correspondante, ce qui est utile pour le débogage.
from sqlalchemy import create_engine engine = create_engine('mysql+pymysql://$user:$password@$host:$port/$db?charset=utf8mb4', echo=True)
Pour moi personnellement, lors de l'introduction du framework ORM, mon projet fera référence au modèle MVC pour la conception suivante. Parmi eux, model stocke certains modèles de base de données, c'est-à-dire les classes Python mappées aux tables de base de données ; model_op stocke les opérations correspondant à chaque modèle, c'est-à-dire l'ajout, la suppression, la vérification et la modification lorsque l'appelant (comme main.py) ; effectue des opérations de base de données, il lui suffit d'appeler la couche model_op, vous n'avez pas besoin de vous soucier de la couche modèle pour réaliser le découplage.
├── main.py ├── model │ ├── __init__.py │ ├── base_model.py │ ├── ddl.sql │ └── py_orm_model.py └── model_op ├── __init__.py └── py_orm_model_op.py
Par exemple, si nous avons une telle table de test
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 '测试表';
Dans le framework ORM, le résultat du mappage est la classe Python ci-dessous
# 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='更新时间')
Tout d'abord, nous pouvons voir l'héritage PyOrmModel. La classe de base est une classe de base fournie par sqlalchemy. Elle effectuera quelques vérifications sur la classe Python que nous avons déclarée. Je l'ai mise dans base_model.
# 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)
Deuxièmement, chaque classe Python doit contenir l'attribut __tablename__, sinon la table correspondante est introuvable.
Troisièmement, il existe deux façons de créer une table de données. La première consiste bien sûr à la créer manuellement dans MySQL. Tant qu'il n'y a aucun problème avec la définition de votre classe Python, elle peut fonctionner normalement ; via le framework ORM, comme ci-dessous :
# main.py # 注意这里的导入路径,Base创建表时会寻找继承它的子类,如果路径不对,则无法创建成功 from sqlachlemy_lab import Base, engine if __name__ == '__main__': Base.metadata.create_all(engine)
Effet de création :
... 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) )
Quatrièmement, concernant les attributs de champ
Il est mentionné dans la documentation SQLAlchemy que les ajouts, suppressions et modifications à la base de données sont effectués via des sessions.
>>> 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()
Comme ci-dessus, nous pouvons voir que pour chaque opération, nous devons acquérir, soumettre et libérer la session. C'est trop redondant et gênant, nous effectuons donc généralement une couche d'encapsulation.
1. Utilisez le gestionnaire de contexte pour gérer l'annulation et la fermeture anormales de la session. Cette partie est presque cohérente avec l'article référencé.
# 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. Ajoutez deux méthodes dans PyOrmModel pour la conversion entre modèle et dict
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 Encapsulation des opérations de base de données Différent de l'article de référence, j'ai directement appelé la session, afin que l'appelant n'ait pas besoin d'y prêter attention. la couche de modèle et réduire le couplage.
# 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. Appelant
# main.py from sqlachlemy_lab.model_op import PyOrmModelOp if __name__ == '__main__': PyOrmModelOp.save_data({'id': 1, 'name': 'test', 'attr': {}})
Pour le code complet, veuillez consulter :
https://github.com/yangancode/python_lab/tree/master/sqlachlemy_lab
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!