Обрабатывать поля в модели 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))
Другие вопросы по тегам