Как использовать зефир для сериализации поля sqlalchemy?
В эти дни я просто запускаю простой проект, называемый flask_wiki, и использую следующие расширения фляги:
- Колба-SQLAlchemy
- Колба-Restful
- Зефир
Что ж, я только что обнаружил, что проект MarshMallow предоставляет класс ModelSchema, который считывает все поля из моей модели SQLAlchemy и предоставляет полностью автоматизированный (де) сериализатор.
В моем случае я создал поле GUID, которое не зависит от RDBM, и вставил его в свою модель Sqlalchemy следующим образом:
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
GUIDField реализован так:
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)
Код для создания тестовых объектов (через микшер) работает; все направляющие созданы и проверены правильно.
Имея это в виду, я только что создал следующее поле сериализатора MarshMallow:
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
Наконец, я создал 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)
Я пытался использовать этот последний код с и без вставки поля guid, но во всех случаях возникает следующая ошибка:
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'>.
Итак, я наконец спрашиваю: как использовать зефир для сериализации поля sqlalchemy?
2 ответа
Вам нужно создать свой собственный конвертер. Попробуйте что-то вроде этого:
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")
Вы также можете увидеть эту ссылку для помощи. Я надеюсь, что это помогло и извините за мой плохой английский
Согласно тому, что я прочитал в документации, вы можете указать атрибут model_converter в вашем ModelSchema
Мета класс. ModelConverter
класс имеет SQLA_TYPE_MAPPING
атрибут, который вы можете переопределить в подклассе, чтобы добавить свое настраиваемое поле GUID к типам, обнаруженным автоматическим генератором схемы.
Тем не менее, я никогда не использовал его, поэтому я не знаю, сработает ли это или нет.