在使用 SQLAlchemy 获取数据时,妥善处理诸如密码之类的敏感信息至关重要。本文展示了在 SQLAlchemy 中排除查询结果中密码信息的各种方法。
使用延迟加载列
延迟加载列加载允许特定列仅在被访问时才被加载。将密码列标记为延迟加载:
from sqlalchemy.orm import deferred
# Define your User model
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String)
email = Column(String)
password = deferred(Column(String))
# Query without loading password
dummy_query = session.query(User).all()
for user in dummy_query:
print(user.username) # Password is not queried yet
按需加载列
如果您在某些情况下需要密码,但在其他情况下不需要,请按需加载:
# Load password on demand
user_with_pass = session.query(User).options(undefer('password')).get(some_user_id)
print(user_with_pass.password)
使用load_only()
要显式地告诉SQLAlchemy加载哪些列,使用load_only()函数:
from sqlalchemy.orm import load_only
# Query only specific columns excluding the password
dummy_query = session.query(User).options(load_only('id', 'username', 'email')).all()
直接排除列
也可以直接查询除‘ password ’列外的所有列:
# Exclude password by not mentioning it
query = session.query(User.id, User.username, User.email).all()
安全方面的混合属性
使用 SQLAlchemy 的混合属性将密码封装在一个计算属性中,该属性不会明确地暴露密码:
from sqlalchemy.ext.hybrid import hybrid_property
# Add a hybrid property that doesn't return the password
class User(Base):
...
@hybrid_property
def safe_data(self):
return { 'id': self.id, 'username': self.username, 'email': self.email }
# Query and use safe_data instead of the row
dummy_query = session.query(User).all()
for user in dummy_query:
print(user.safe_data)
自动排除
对于更高级的方法,覆盖基类中的方法以默认情况下排除密码:
class SafeQuery(Query):
def instances(self, result, context):
"""Override the default instance creation method to exclude passwords"""
return (self._safe_instance(row) for row in result)
def _safe_instance(self, row):
data = super().instances(row)
del data['password']
return data
高级用法:覆盖查询类
对于跨不同查询经常需要排除列的情况,你可以覆盖默认的Query类,以在默认情况下包含排除功能。这可能是一个更高级的主题,因为它需要很好地理解自定义SQLAlchemy类。
class ExcludingQuery(Query):
def exclude(self, *columns):
return self.with_entities(*[c for c in self.column_descriptions if c['expr'] not in columns])
# Replace the query_property on the Base class
Base.query = session.query_property(query_cls=ExcludingQuery)
# Now you can write queries like:
query = User.query.exclude(User.nickname)
for user in query.all():
print(user.name, user.fullname)
在实践中,这些方法可以根据具体需求组合使用。在选择一种方法时,理解对代码性能和可读性的影响是很重要的。
最后总结
总之,SQLAlchemy提供了各种方法来从查询结果中排除密码或任何敏感信息。明智地使用这些技术来确保应用程序的数据保持安全。