如何使用棉花糖序列化自定义sqlalchemy字段? [英] How to use marshmallow to serialize a custom sqlalchemy field?
问题描述
我刚刚开始一个名为flask_wiki的简单项目,我正在使用一些扩展插件,如下所示:
我的情况是,我创建了一个与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屋!