2015-02-04 2 views
3

Я использую колбовую SQLAlchemy и есть модель со следующей колонки:Почему SQLAlchemy инициализирует поле hstore как null?

class Item(Model): 
    misc = Column(MutableDict.as_mutable(postgresql.HSTORE), nullable=False, 
        server_default='', 
        default=MutableDict.as_mutable(postgresql.HSTORE)) 

При попытке назначить поля к объекту модели, то кажется, что misc столбец не является None, а не пустой Dict:

my_item = Item() 
my_item.misc["foo"] = "bar" 
# TypeError: 'NoneType' object does not support item assignment 

Как настроить модель так, чтобы новые объекты инициализировались пустым словарем?

ответ

3

Здесь есть две проблемы. Во-первых, default должен быть питоном Python, а не повторением типа столбца. Во-вторых, default не используется при инициализации новых экземпляров, только при совершении экземпляров без значения, установленного для этого столбца. Поэтому вам нужно дополнительно добавить значение по умолчанию во время инициализации.

from sqlalchemy.dialects.postgresql import HSTORE 
from sqlalchemy.ext.mutable import MutableDict 

class Item(db.Model): 
    misc = db.Column(MutableDict.as_mutable(HSTORE), nullable=False, default={}, server_default='') 

    def __init__(self, **kwargs): 
     kwargs.setdefault('misc', {}) 
     super(Item, self).__init__(**kwargs) 
item = Item() 
item.misc['foo'] = 'bar' 

На этой ноте, нет никакого смысла в установлении как default и server_default если вы только когда-либо будет использовать это с Python. Впрочем, нет никакого вреда.


Я предполагаю, что вы знаете, что вы хотите HSTORE в этом конкретном случае, но я также отметить, что PostgreSQL имеет более общий JSON и типы JSONB в настоящее время.

+0

Это то, что сработало для меня: 'misc = db.Column (MutableDict.as_mutable (HSTORE), nullable = False, server_default = db.text (" '' "))). Таким образом, я получаю 'DEFAULT '' :: hstore' в столбце' misc' в postgres, что приводит к пустым 'dict' по умолчанию в python. – robkorv

0

Возможно, это более простой способ сделать это, но один из способов - создать собственный тип столбца, который преобразует значения из базы данных и обратно.

Вот пример из документации, сериализуемой/десериализует JSON в поле VARCHAR:

http://docs.sqlalchemy.org/en/latest/orm/extensions/mutable.html#establishing-mutability-on-scalar-column-values

from sqlalchemy.types import TypeDecorator, VARCHAR 
import json 

class JSONEncodedDict(TypeDecorator): 
    "Represents an immutable structure as a json-encoded string." 

    impl = VARCHAR 

    def process_bind_param(self, value, dialect): 
     if value is not None: 
      value = json.dumps(value) 
     return value 

    def process_result_value(self, value, dialect): 
     if value is not None: 
      value = json.loads(value) 
     return value 

В вашем случае, вы можете проверить, если value не None и возвращает пустую dict() вместо этого, и при записи в db вы должны проверить, является ли value пустой dict и вместо этого напишите None.

Если вы идете по этому маршруту, взгляните на материал изменчивости немного дальше, поэтому изменения в JSONEncodedDict будут замечены и размыты. Похоже, вы уже знаете об этом, но только для тех, кто читает это.

Надеюсь, что это поможет.

+0

Но это не ХОСТЕР. И так как это PostgreSQL, там встроены типы JSON и JSONB, если это то, что нужно. – davidism

Смежные вопросы