Flask-SQLAlchemy中的LocalProxy对象

Nic*_*ack 8 python sqlalchemy werkzeug flask flask-sqlalchemy

我在Flask应用程序中使用了很多werkzeug.local.LocalProxy对象.它们应该是对象的完美替身,但它们并不是真的,因为它们没有正确响应type()或instanceof().

SQLAlchemy完全不喜欢它们.如果我将LocalProxy创建为SQLAlchemy记录,则SQLAlchemy会将其视为None.如果我将LocalProxy传递给更简单的类型,它只是说它是错误的类型.

这是Flask-SQLAlchemy使用LocalProxy时间不好的一个例子.

你们怎么处理这个问题?只需调用_get_current_object()很多?如果SQLAlchemy或Flask-SQLAlchemy可以更自然地自动处理这些LocalProxy对象,那将是非常酷的,特别是考虑到Flask-Login使用它们,并且几乎每个人都使用它,对吧?

我正在考虑将这个函数添加到我的项目来处理它,并在将它们传递给sqlalchemy之前将我的任何本地代理包装在其中:

from werkzeug.local import LocalProxy

def real(obj):
    if isinstance(obj, LocalProxy):
        return obj._get_current_object()
    return obj
Run Code Online (Sandbox Code Playgroud)

小智 0

我修补了 所使用的驱动程序SQLAlchemy,但我担心这不是最通用的解决方案。

from flask_sqlalchemy import SQLAlchemy as FlaskSQLAlchemy
from sqlalchemy.engine import Engine
from werkzeug.local import LocalProxy


class SQLAlchemy(FlaskSQLAlchemy):
    """Implement or overide extension methods."""

    def apply_driver_hacks(self, app, info, options):
        """Called before engine creation."""
        # Don't forget to apply hacks defined on parent object.
        super(SQLAlchemy, self).apply_driver_hacks(app, info, options)

        if info.drivername == 'sqlite':
            from sqlite3 import register_adapter

            def adapt_proxy(proxy):
                """Get current object and try to adapt it again."""
                return proxy._get_current_object()

            register_adapter(LocalProxy, adapt_proxy)

        elif info.drivername == 'postgresql+psycopg2':  # pragma: no cover
            from psycopg2.extensions import adapt, register_adapter

            def adapt_proxy(proxy):
                """Get current object and try to adapt it again."""
                return adapt(proxy._get_current_object())

            register_adapter(LocalProxy, adapt_proxy)

        elif info.drivername == 'mysql+pymysql':  # pragma: no cover
            from pymysql import converters

            def escape_local_proxy(val, mapping):
                """Get current object and try to adapt it again."""
                return converters.escape_item(
                    val._get_current_object(),
                    self.engine.dialect.encoding,
                    mapping=mapping,
                )

            converters.encoders[LocalProxy] = escape_local_proxy
Run Code Online (Sandbox Code Playgroud)

原始来源可以在这里找到。