2013-09-22 56 views
4

如何使用Flask-Admin更新HSTORE字段?我們如何使用Flask-Admin更新HSTORE字段?

常規ModelView在編輯視圖中不顯示HSTORE字段。它什麼都沒顯示。根本沒有控制權。在列表視圖中,它顯示一個包含JSON表示法的數據的列。這對我來說沒問題。

使用自定義ModelView,我可以將HSTORE字段更改爲TextAreaField。這將在編輯視圖中顯示JSON符號中的HSTORE字段。但我無法編輯/更新它。在列表視圖中,它仍以JSON表示法顯示對象。對我來說看起來很好。

class MyView(ModelView): 
    form_overrides = dict(attributes=fields.TextAreaField) 

當我嘗試保存/編輯JSON,我收到此錯誤:

sqlalchemy.exc.InternalError 
InternalError: (InternalError) Unexpected end of string 
LINE 1: UPDATE mytable SET attributes='{}' WHERE mytable.id = ... 
             ^
'UPDATE mytable SET attributes=%(attributes)s WHERE mytable.id = %(mytable_id)s' {'attributes': u'{}', 'mytable_id': 14L} 

現在 - 使用代碼,我可以得到的東西保存到HSTORE領域:

class MyView(ModelView): 
    form_overrides = dict(attributes=fields.TextAreaField) 
    def on_model_change(self, form, model, is_created): 
     model.attributes = {"a": "1"} 
     return 

這基本上覆蓋了模型並將其放入其中。然後我可以在列表視圖和編輯視圖中看到該對象。仍然不夠好 - 我想保存/編輯用戶輸入的對象。

我試圖解析並將表單中的內容保存到JSON中並退出。這不起作用:

class MyView(ModelView): 
    form_overrides = dict(attributes=fields.TextAreaField) 

    def on_model_change(self, form, model, is_created): 
     x = form.data['attributes'] 
     y = json.loads(x) 
     model.attributes = y 
     return 

json.loads(X)這樣說:

​​3210

,這裏是失敗的一些採樣輸入:

{u's': u'ff'} 
{'s':'ff'} 

然而,這個輸入作品:

{} 

空白也可以工作

這是我的SQL表:

CREATE TABLE mytable (
    id BIGSERIAL UNIQUE PRIMARY KEY, 
    attributes hstore 
); 

這是我的SQA型號:

class MyTable(Base): 
    __tablename__ = u'mytable' 

    id = Column(BigInteger, primary_key=True) 
    attributes = Column(HSTORE) 

這裏是我加的觀點對管理對象

admin.add_view(ModelView(models.MyTable, db.session)) 

添加查看使用自定義模型視圖

admin.add_view(MyView(models.MyTable, db.session)) 

但我不這樣做,同時這些觀點 - 我得到一個藍圖名稱衝突的錯誤 - 單獨的問題)

我也嘗試使用表單域轉換器。我無法實際打到代碼。

class MyModelConverter(AdminModelConverter): 
    def post_process(self, form_class, info): 
     raise Exception('here I am') #but it never hits this 
     return form_class 

class MyView(ModelView): 
    form_overrides = dict(attributes=fields.TextAreaField) 

回答

6

答案給你多一點,然後要求所有它「伸出」的

拳hstore能夠實際存儲JSON,而不是鍵值 所以這種結構也行:

{"key":{"inner_object_key":{"Another_key":"Done!","list":["no","problem"]}}} 

所以,首先你的模型視圖中應該使用自定義轉換器

class ExtendedModelView(ModelView): 
    model_form_converter=CustomAdminConverter 

轉換器本身應該知道如何使用hstore方言:

class CustomAdminConverter(AdminModelConverter): 
    @converts('sqlalchemy.dialects.postgresql.hstore.HSTORE') 
    def conv_HSTORE(self, field_args, **extra): 
     return DictToHstoreField(**field_args) 

這一個,你可以看到使用自定義WTForms領域,其將在兩個方向上的數據:

class DictToHstoreField(TextAreaField): 
    def process_data(self, value): 
     if value is None: 
      value = {} 
     else: 
      for key,obj in value.iteritems(): 
       if (obj.startswith("{") and obj.endswith("}")) or (obj.startswith("[") and obj.endswith("]")): 
        try: 
         value[key]=json.loads(obj) 
        except: 
         pass # 

     self.data=json.dumps(value) 

    def process_formdata(self, valuelist): 
     if valuelist: 
      self.data = json.loads(valuelist[0]) 
      for key,obj in self.data.iteritems(): 
       if isinstance(obj,dict) or isinstance(obj,list): 
        self.data[key]=json.dumps(obj) 
       if isinstance(obj,int): 
        self.data[key]=str(obj) 

的最後一步將是實際使用這個數據在應用程序

我沒有使它成爲SQLalchemy的通用好方法,因爲它與flask-restful一起使用,所以我只在一個方向上採用flask-restful,但我認爲這很容易得到這個想法從這裏開始做其餘的部分。

如果你的情況是簡單的鍵值存儲,所以不應該做任何addaly應該完成,只要按原樣使用它。 但是如果你想解開JSON在代碼的某個地方,這是簡單的這樣每當你使用它,只是包裝在功能

if (value.startswith("{") and value.endswith("}")) or (value.startswith("[") and value.endswith("]")): 
     value=json.loads(value) 

通過擴展創建動力場實際很好非JSON的方式進行數據的編輯也可以FormField並添加一些JavaScript添加/刪除字段,但這是完全不同的故事,在我的情況下,我需要實際的JSON存儲,與二十一點和列表:)

+0

自定義字段部分,有一個在文檔稍微簡單的例子:HTTPS:/ /wtforms.readthedocs.org/en/latest/fields.html#custom-fields –

+0

這對hstore有幫助嗎? –

3

雖然,這可能不是你的問題的答案,但默認情況下,SQLAlchemy的ORM不檢測HSTORE字段值的就地更改。但幸運的是有一個解決方案:SQLAlchemy的的MutableDict類型:

from sqlalchemy.ext.mutable import MutableDict 

class MyClass(Base): 
    __tablename__ = 'mytable' 

    id = Column(Integer, primary_key=True) 
    attributes = Column(MutableDict.as_mutable(HSTORE)) 

現在,當你改變就地東西:

my_object.attributes.['some_key'] = 'some value' 

hstore場將session.commit()後更新。

+0

對,忘了這個也需要:) – Tigra

+0

你救了我的一天。 –

4

正在處理postgres JSON數據類型。上述解決方案很好地進行了小的修改。

試圖

'sqlalchemy.dialects.postgresql.json.JSON', 
'sqlalchemy.dialects.postgresql.JSON', 
'dialects.postgresql.json.JSON', 
'dialects.postgresql.JSON' 

以上版本沒有工作。

最後下列變化工作

@converts('JSON') 

而改變類DictToHstoreField以下幾點:

class DictToJSONField(fields.TextAreaField): 
    def process_data(self, value): 
     if value is None: 
      value = {} 

     self.data = json.dumps(value) 

    def process_formdata(self, valuelist): 
     if valuelist: 
      self.data = json.loads(valuelist[0]) 
     else: 
      self.data = '{}' 
相關問題