如何使用棉花糖序列化自定义sqlalchemy字段? [英] How to use marshmallow to serialize a custom sqlalchemy field?

查看:372
本文介绍了如何使用棉花糖序列化自定义sqlalchemy字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始一个名为flask_wiki的简单项目,我正在使用一些扩展插件,如下所示:


  • Flask-SQLAlchemy
  • ,我刚刚发现MarshMallow项目提供了一个名为ModelSchema的类,它读取我的SQLAlchemy模型中的所有字段,并提供一个完全自动的(de)serialializer。



    我的情况是,我创建了一个与RDBM无关的'GUID'字段,并将其插入到我的Sqlalchemy模型中,如下所示:

      .ext.sqlalchemy从flask_wiki.backend.custom_fields导入SQLAlchemy 
    导入GUIDField
    $ b $ class Page(db.Model):

    实现页面模型。

    guid = db.Column(GUIDField,primary_key = True,default = uuid.uuid4)
    name = db.Column(db.String,nullable = False)
    raw_content = db.Column(db.Text)
    rendered_content = db.Co lumn(db.Text)
    $ b def __repr __(self):
    return self .__ str __()
    $ b def __str __(self):
    return self .name

    GUIDField是这样实现的:
    $ b $从sqlalchemy.types中导入TypeDecorator,CHAR
    导入uuid


    class GUIDField(TypeDecorator):
    #$

     独立于平台的GUID实现使用少量的内存。 
    impl = CHAR
    $ b $ def load_dialect_impl(self,dialect):
    返回dialect.type_descriptor(CHAR(32))

    def process_bind_param(self,值,方言):
    如果value是None:
    返回值
    else:
    如果是isinstance(value,uuid.UUID):
    返回value.bytes_le

    def process_result_value(self,value,dialect):
    如果value是None:
    返回值
    else:
    return uuid.UUID(bytes_le = value)

    创建测试对象的代码(通过混音器)正在工作;所有的guid生成和验证正确。

    有了这个想法,刚刚创建了以下MarshMallow序列化程序字段:

     从marshmallow导入字段
    导入uuid


    类GUIDSerializationField(fields.Field):
    def _serialize ,value,attr,obj):
    如果value是None:
    返回值
    else:
    如果是isinstance(value,uuid.UUID):
    return str值)
    else:
    return None

    最后,我创建了SerializerClass:

      from flask_wiki.backend.backend从flask_wiki.backend.custom_serialization_fields导入marsh 
    导入GUIDSerializationField $ b $ from flask_wiki .backend.models import Page
    from marshmallow import fields

    $ b class class PageSchema(marsh.ModelSchema):
    class Meta:
    model = Page

    guid = GU IDSerializationField()

    $ b page_schema = PageSchema()
    Page_schema = PageSchema(many = True)

    我试图在使用和不使用guid字段的情况下使用最后一个代码,但是在所有情况下都会出现以下错误:

     Traceback(最近一次调用最后一次):
    在< module>文件中的/home/arthas/dev/flask-wiki/flask_wiki/wiki.py第3行。
    from flask_wiki.backend import backend
    文件/home/arthas/dev/flask-wiki/flask_wiki/backend/__init__.py,第1行,在< module>
    导入flask_wiki.backend.routes
    文件/home/arthas/dev/flask-wiki/flask_wiki/backend/routes.py,第2行,在< module>
    from flask_wiki.backend.views import PageView
    文件/home/arthas/dev/flask-wiki/flask_wiki/backend/views.py,第3行,位于< module>
    from flask_wiki.backend.serializers import pages_schema,page_schema
    文件/home/arthas/dev/flask-wiki/flask_wiki/backend/serializers.py,第7行,在< module>
    class PageSchema(marsh.ModelSchema):
    文件/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow/schema.py,行116,在__new__
    dict_cls = dict_cls
    文件/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/schema.py,第53行,在get_declared_fields
    declared_fields = mcs .get_fields(转换器,opts)
    文件/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/schema.py,第77行,在get_fields
    返回转换器.fields_for_model(opts.model,fields = opts.fields,exclude = opts.exclude)
    文件/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py第75行,在fields_for_model
    field = self.property2field(prop)
    文件/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py,第93行,在property2field
    field_class = self._get_field_class_for_property(prop)
    文件/home/arthas/env/wiki/lib/python3.5/si te-packages / marshmallow_sqlalchemy / convert.py,第151行,在_get_field_class_for_property
    field_cls = self._get_field_class_for_column(column)
    文件/home/arthas/env/wiki/lib/python3.5/site -packages / marshmallow_sqlalchemy / convert.py,第121行,在_get_field_class_for_column
    中返回self._get_field_class_for_data_type(column.type)
    文件/home/arthas/env/wiki/lib/python3.5/site -packages / marshmallow_sqlalchemy / convert.py,第143行,在_get_field_class_for_data_type
    '找不到类型{0}。'.format(types [0])的字段列)
    marshmallow_sqlalchemy.exceptions.ModelConversionError :无法找到< class'flask_wiki.backend.custom_fields.GUIDField'>类型的字段列。

    所以,我终于问:如何使用棉花糖来序列化一个自定义的sqlalchemy字段?

    解决方案

    您需要创建自己的Converter。
    尝试如下所示:

     从flask_wiki.backend.models导入uuid 
    import Page
    from flask_wiki.backend.backend从marshmallow_sqlalchemy.convert导入marsh
    从flask_wiki.backend.custom_fields导入ModelConverter
    从marshmallow导入字段导入GUIDField



    #你在覆盖SQLAlchemy类型列表,添加你的自定义类型
    class GUIDConverter(ModelConverter):
    SQLA_TYPE_MAPPING = dict(
    list(ModelConverter.SQLA_TYPE_MAPPING.items()) +
    [(GUIDField,fields.Str)]

    $ b $ class GUIDSerializationField(fields.Field):
    def _serialize(self,value,attr,obj) :
    如果value是None:
    返回值
    else:
    如果是isinstance(value,uuid.UUID):
    return str(value)
    else :
    返回无
    $ b $ class class PageSchema(marsh.ModelSchema):
    class Meta:
    model = Page
    model_converter = GUIDConverter#告诉Marshmallow使用这个模型的自定义转换器

    guid = GUIDSerializationField(attribute =guid)

    您也可以看到这个链接寻求帮助。
    我希望对我的英文不好,帮助和抱歉

    I just start a simple project called flask_wiki this days and I'm using some flask extensions as the follows:

    • Flask-SQLAlchemy
    • Flask-Restful
    • MarshMallow

    Well, I just discovered that the MarshMallow project provides a class called 'ModelSchema', which reads all fields from my SQLAlchemy Model and provide a fully automated (de)serialializer.

    In my case, I created a 'GUID' Field which is RDBM agnostic and inserted it on my Sqlalchemy model as follows:

    from flask.ext.sqlalchemy import SQLAlchemy
    from flask_wiki.backend.custom_fields import GUIDField
    
    class Page(db.Model):
        """
        Implements the Page Model.
        """
        guid = db.Column(GUIDField, primary_key=True, default=uuid.uuid4)
        name = db.Column(db.String, nullable=False)
        raw_content = db.Column(db.Text)
        rendered_content = db.Column(db.Text)
    
        def __repr__(self):
            return self.__str__()
    
        def __str__(self):
            return self.name
    

    The GUIDField is implemented is this way:

    from sqlalchemy.types import TypeDecorator, CHAR
    import uuid
    
    
    class GUIDField(TypeDecorator):
        # Platform independent GUID Implementation that uses little endianess.
        impl = CHAR
    
        def load_dialect_impl(self, dialect):
            return dialect.type_descriptor(CHAR(32))
    
        def process_bind_param(self, value, dialect):
            if value is None:
                return value
            else:
                if isinstance(value, uuid.UUID):
                    return value.bytes_le
    
        def process_result_value(self, value, dialect):
            if value is None:
                return value
            else:
                return uuid.UUID(bytes_le=value)
    

    The code for create test objects (through mixer) is working; all the guids are generated and verified correctly.

    With this in mind, a just created the following MarshMallow Serializer Field:

    from marshmallow import fields
    import uuid
    
    
    class GUIDSerializationField(fields.Field):
        def _serialize(self, value, attr, obj):
            if value is None:
                return value
            else:
                if isinstance(value, uuid.UUID):
                    return str(value)
                else:
                    return None
    

    Finally, I created the SerializerClass:

    from flask_wiki.backend.backend import marsh
    from flask_wiki.backend.custom_serialization_fields import GUIDSerializationField
    from flask_wiki.backend.models import Page
    from marshmallow import fields
    
    
    class PageSchema(marsh.ModelSchema):
        class Meta:
            model = Page
    
        guid = GUIDSerializationField()
    
    
    page_schema = PageSchema()
    pages_schema = PageSchema(many=True)
    

    I tried to use this last code with and without inserting the guid field, but in all cases the following error occurs:

    Traceback (most recent call last):
      File "/home/arthas/dev/flask-wiki/flask_wiki/wiki.py", line 3, in <module>
        from flask_wiki.backend import backend
      File "/home/arthas/dev/flask-wiki/flask_wiki/backend/__init__.py", line 1, in <module>
        import flask_wiki.backend.routes
      File "/home/arthas/dev/flask-wiki/flask_wiki/backend/routes.py", line 2, in <module>
        from flask_wiki.backend.views import PageView
      File "/home/arthas/dev/flask-wiki/flask_wiki/backend/views.py", line 3, in <module>
        from flask_wiki.backend.serializers import pages_schema, page_schema
      File "/home/arthas/dev/flask-wiki/flask_wiki/backend/serializers.py", line 7, in <module>
        class PageSchema(marsh.ModelSchema):
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow/schema.py", line 116, in __new__
        dict_cls=dict_cls
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/schema.py", line 53, in get_declared_fields
        declared_fields = mcs.get_fields(converter, opts)
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/schema.py", line 77, in get_fields
        return converter.fields_for_model(opts.model, fields=opts.fields, exclude=opts.exclude)
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py", line 75, in fields_for_model
        field = self.property2field(prop)
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py", line 93, in property2field
        field_class = self._get_field_class_for_property(prop)
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py", line 151, in _get_field_class_for_property
        field_cls = self._get_field_class_for_column(column)
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py", line 121, in _get_field_class_for_column
        return self._get_field_class_for_data_type(column.type)
      File "/home/arthas/env/wiki/lib/python3.5/site-packages/marshmallow_sqlalchemy/convert.py", line 143, in _get_field_class_for_data_type
        'Could not find field column of type {0}.'.format(types[0]))
    marshmallow_sqlalchemy.exceptions.ModelConversionError: Could not find field column of type <class 'flask_wiki.backend.custom_fields.GUIDField'>.
    

    So, I finally ask: how to use marshmallow to serialize a custom sqlalchemy field?

    解决方案

    You need to create your own Converter. Try something like this:

    import uuid
    from flask_wiki.backend.models import Page
    from flask_wiki.backend.backend import marsh
    from marshmallow_sqlalchemy.convert import ModelConverter
    from flask_wiki.backend.custom_fields import GUIDField
    from marshmallow import fields
    
    
    #Here you are overwriting the list of types of the SQLAlchemy, adding your custom type 
    class GUIDConverter(ModelConverter):
        SQLA_TYPE_MAPPING = dict(
            list(ModelConverter.SQLA_TYPE_MAPPING.items()) + 
            [(GUIDField, fields.Str)] 
        )
    
    class GUIDSerializationField(fields.Field):
        def _serialize(self, value, attr, obj):
            if value is None:
                return value
            else:
                if isinstance(value, uuid.UUID):
                    return str(value)
                else:
                    return None
    
    class PageSchema(marsh.ModelSchema):
        class Meta:
            model = Page        
            model_converter = GUIDConverter #Tell to Marshmallow to use your custom converter for this model
    
        guid = GUIDSerializationField(attribute="guid")
    

    You can also see this link for help. I hope it helped and sorry for my bad english

    这篇关于如何使用棉花糖序列化自定义sqlalchemy字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆