Обрабатывать поля в модели SQLAlchemy (используя flask_sqlalchemy)
Я использую SQLAlchemy через flask_sqlalchemy. Модель получает данные из HTML-форм. Я хотел бы, чтобы этот ввод был лишен каких-либо тегов. Вместо того, чтобы делать это несколько раз в коде перед присваиванием, я подумал, что может быть лучше реализовать это как-то в объекте модели.
Возможности, о которых я мог подумать:
- Получите собственные типы столбцов
- Оберните прокси-класс вокруг типов столбцов
- Определите вид декоратора, который делает выше
- Изменить объект модели для перехвата назначений
Первые три решения кажутся более элегантными, но я не понимаю, как мне нужно их реализовать. Основная причина в том, что я не понимаю, как именно SQLAlchemy извлекает структуру таблицы и типы столбцов из переменных столбца, и как обрабатывается их присвоение, особенно при доступе через класс flask_sqlalchemy.
Я поиграл с последним вариантом в списке выше, и придумал это (частичное) решение:
import bleach
class Example(db.Model):
__tablename__ = 'examples'
id = db.Column(db.Integer, primary_key=True)
field1 = db.Column(db.Text)
field2 = db.Column(db.String(64))
_bleach_columns = ('field1', 'field2')
def __init__(self, **kwargs):
if kwargs is not None:
for key in Example._bleach_columns:
kwargs[key] = bleach.clean(kwargs[key], tags=[], strip=True)
super(Example, self).__init__(**kwargs)
Это работает при создании объектов с использованием Example(field1='foo', field2='bar')
, Однако я не уверен, как справиться с назначением отдельных полей. Я думал о чем-то вроде этого, но не уверен насчет частей, помеченных как ASSIGN:
def __setattr__(self, attr, obj):
if(attr in Example._bleach_columns):
ASSIGN(..... , bleach.clean(obj, tags=[], strip=True))
else:
ASSIGN(..... , obj)
В целом, у меня сложилось впечатление, что это не самый лучший способ фильтрации тегов. Поэтому я был бы признателен за любую подсказку о том, как наилучшим образом реализовать это поведение, в идеале с декоратором новых типов столбцов.
Похоже, это можно сделать с помощью TypeDecorator ( ссылка), который применяет отбеливатель в process_bind_param
, Однако я не мог понять, как применить этот декоратор к определению столбца на основе flask_sqlalchemy в классе, производном от db.Model, выше.
1 ответ
Мне наконец удалось решить это... что было легко, как обычно, когда понял, о чем идет речь.
Прежде всего нужно было понять, что db.Column
такой же, как в SQLAlchemy column
, Таким образом, я мог бы использовать тот же синтаксис. Для реализации строк переменной длины я использовал фабрику классов для возврата декораторов. Если есть другое решение для реализации длины, мне было бы интересно услышать об этом. Во всяком случае, вот код:
def bleachedStringFactory(len):
class customBleachedString(types.TypeDecorator):
impl = types.String(len)
def process_bind_param(self, value, dialect):
return bleach.clean(value, tags=[], strip=True)
def process_result_value(self, value, dialect):
return value
return customBleachedString
class Example(db.Model):
__tablename__ = 'examples'
id = db.Column(db.Integer, primary_key=True)
field1 = db.Column(bleachedStringFactory(64), unique=True)
field2 = db.Column(bleachedStringFactory(128))