在Flask中使用MongoDB:Flask-MongoEngine
在Flask中使用MongoEngine,需要通過Flask-MongoEngine包來對MongoEngine進行配置。Flask-MongoEngine是MongoEngine的Flask封裝,針對Flask對MongoEngine做出了一些拓展,而MongoEngine則是在PyMongo的基礎上構建的一個類似於SQLAlchemy的物件文件對映器(Object-Document Mapper, ODM),為使用者提供基本的資料模型以及型別約束,並對PyMongo的資料查詢做了進一步的封裝,避免直接書寫MongoDB查詢語句,簡化資料查詢。
PyMongo是MongoDB官方提供的Python庫,將MongoDB CLI中JS風格的查詢語句在Python中進行了封裝,使用者仍然可以在Python中採用和MongoDB CLI中相同的方法操作MongoDB資料庫。但PyMongo本身缺乏型別約束、值校驗、資料模型等特性支援,每一次的查詢操作都需要直接和字典進行互動。
Flask-MongoEngine對MongoEngine做了以下拓展:
- 從
MONGODB_XXX
格式變數中讀取MongoEngine的配置資訊,並自動建立連線。 - 對MongoEngine的查詢
QuerySet
進行了拓展,以支援get_or_404
,first_or_404
,paginate
,paginate_field
。 - 支援直接從MongoEngine模型中生成WTForms表單。
- 支援將MongoEngine作為session儲存後端。
- 為
flask_debugtoolbar
提供MongoEngine查詢跟蹤。 - 通過
app.json_encoder
對Flask預設的JSON編碼器進行拓展,添加了BaseDocument
QuerySet
兩個型別的序列化支援。
資源
Item | Repository | Documents |
---|---|---|
MongoEngine | https://github.com/MongoEngine/mongoengine | https://mongoengine-odm.readthedocs.io/ |
Flask-MongoEngine | https://github.com/MongoEngine/flask-mongoengine | https://flask-mongoengine.readthedocs.io |
快速開始
from flask import Flask from flask_mongoengine import MongoEngine app = Flask(__name__) # 通過MONGODB_SETTINGS配置MongoEngine app.config.from_mapping({ MONGODB_SETTINGS = { 'db': 'test', 'host': 'localhost', 'port': 27017, 'connect': True, 'username': 'test', 'password': '123456', 'authentication_source': 'admin' } }) # 初始化 MongoEngine db = MongoEngine(app) # 定義一個文件 User,MongoEngine 會自動在資料庫中建立一個名為 user 的集合 class User(db.Document): email = db.StringField(required=True) username = db.StringField(required=True, max_length=128, unique=True) def __repr__(self): return 'User(email="{}", username="{}")'.format(self.username, self.password) # 建立一個User文件例項並存儲 user = User(email="[email protected]", username="kikyou", password="123456") user.save() # 通過 objects 屬性訪問集合中的所有文件 # objects 是一個 QuerySet 例項 for user in User.objects[: 5]: print(user) # 通過 username 查詢使用者,並更新 email user = User.objects(username='kikyou').first() user.email = '[email protected]' user.save()
Flask-MongonEngine配置
Flask-MongonEngine通過MONGODB_XXX
格式的配置變數來配置MongoEngine。其支援通過MONGODB_SETTINGS
來設定MongoEngine的整個配置,也支援通過MONGODB_DB
等來直接設定MONGODB_SETTINGS
下的每個子屬性。需要注意的是,只要設定了MONGODB_SETTINGS
變數,其餘的MONGODB_XXX
變數將被忽略。
通過MONGODB_SETTINGS配置MongoEngine
MONGODB_SETTINGS變數是一個字典,其對應著mongoengine中connect函式支援的所有關鍵字。一旦該變數被設定,其他基於MONGODB_XXX格式指定的mongoengine配置資訊將被忽略。
MONGODB_SETTINGS = {
'db': 'appdb',
'host': 'localhost',
'port': 27017,
'connect': True,
'username': 'test',
'password': '123456',
}
完整的引數列表參考mongoengine.connection.register_connection
以及pymongo.mongo_client.MongoClient
。
alias
建立的資料庫連線的別名,預設為default
,通過alias機制可以同時訪問多個MongoDB資料庫。db
將要訪問的資料庫名稱,預設為test
host
MongoDB伺服器地址,預設為localhost
port
MongoDB伺服器埠,預設為27017
username
使用者名稱password
使用者密碼authentication_source
認證源,建立該使用者的資料庫authentication_mechanism
認證機制,不需要設定is_mock
是否使用 mongomockconnect
是否直接連線伺服器,如果為false,則直到第一次操作時才會連線伺服器tz_aware
是否自動識別時區,如果為false,則直接使用本地時間,忽略datetime的時區配置
通過MONGODB_XXX配置MongoEngine
除了通過MONGODB_SETTTINGS直接配置connect的引數外,還可以通過MONGODB_XXX的形式直接指定引數的值,其中XXX對應MONGODB_SETTTINGS中關鍵字的大寫形式,但目前只支援有限關鍵字:
MONGODB_ALIAS
MONGODB_DB
MONGODB_HOST
MONGODB_IS_MOCK
MONGODB_PASSWORD
MONGODB_PORT
MONGODB_USERNAME
MONGODB_CONNECT
MONGODB_TZ_AWARE
Flask-MongoEngine初始化
除了直接使用db = MongoEngine(app)
進行初始化外,Flask-MongoEngine也像其他Flask擴充套件一樣支援將定義和初始化分離。
# project_dir/__init__.py
from flask import Flask
from flask_mongoengine import MongoEngine
# 定義 MongoEngine
db = MongoEngine()
def create_app():
app = Flask(__name__)
# 通過MONGODB_SETTINGS配置MongoEngine
app.config.from_mapping({
MONGODB_SETTINGS = {
'db': 'test',
'host': 'localhost',
'port': 27017,
'connect': True,
'username': 'test',
'password': '123456',
'authentication_source': 'admin'
}
})
db.init(app)
import .models
return app
# project_dir/models.py
class User(db.Document):
email = db.StringField(required=True)
username = db.StringField(required=True, max_length=128, unique=True)
def __repr__(self):
return 'User(email="{}", username="{}")'.format(self.username, self.password)
額外的拓展
為Flask-MongoEngine新增額外的JSON序列化型別支援
Flask-MongoEngine預設為Flask添加了BaseDocument
和QuerySet
型別的序列化支援,但對於常見的ObjectId
以及Datetime
資料型別缺乏支援。
from flask import Flask
from flask_mongoengine import MongoEngine
def override_json_encoder(app: Flask):
from bson import ObjectId
from datetime import date
superclass = app.json_encoder
class _JsonEncoder(superclass):
def default(self, o):
if isinstance(o, ObjectId):
return str(o)
if isinstance(o, date):
return o.isoformat()
return superclass.default(self, o)
app.json = _JsonEncoder
def create_app()
app = Flask(__name__)
# 通過MONGODB_SETTINGS配置MongoEngine
app.config.from_mapping({
MONGODB_SETTINGS = {
'db': 'test',
'host': 'localhost',
'port': 27017,
'connect': True,
'username': 'test',
'password': '123456',
'authentication_source': 'admin'
}
})
override_json_encoder(app)
db.init(app)
import .models
return app
注:datetime
是date
的子類。
Q&A
編輯器/pylint提示“Instance of 'MongoEngine' has no 'StringField' member”
Flask-MongoEngine在初始化時,為MongoEngine類通過setattr
方法動態注入mongoengine
和mongoengine.fields
的所有屬性,但pylint在進行靜態檢測時,無法找到動態注入的屬性。
解決方法1:直接通過mongoengine.fields.XXXField
引用。
import mongoengine.fields as fields
class User(db.Document):
email = fields.StringField(required=True)
username = fields.StringField(required=True, max_length=128, unique=True)
password = fields.StringField(max_length=256)
解決方法2:禁用pylint錯誤報告。
# pylint: disable=no-member
value = db.StringField(max_length=200) # no error
參考:
資料庫連線提示認證失敗(認證資料庫未配置)
MongoDB支援在不同的資料庫上建立不同的使用者,即使這些使用者的使用者名稱相同。如果將要訪問的資料庫與使用者所在的資料庫不一致,而在連線時只配置將要訪問的資料庫,沒有配置認證資料庫,將產生認證錯誤。
需要通過MONGODB_SETTINGS
變數配置authentication_source
引數,指定使用者所在的資料庫。
MONGODB_SETTINGS = {
'db': 'appdb',
'host': 'localhost',
'port': 27017,
'connect': True,
'username': 'test',
'password': '123456',
'authentication_source': 'admin'
}