potion
potion copied to clipboard
Using Archive recipe and filtering
In order to use soft-deletes, I tried to used the recipe (https://potion.readthedocs.io/en/latest/recipes.html#archivingresource) but filtering resources are not working anymore.
from flask_potion import ModelResource, fields
from flask_potion.contrib.alchemy import SQLAlchemyManager
from flask_potion.exceptions import ItemNotFound
from flask_potion.routes import Route
from flask_potion.instances import Instances
from enum import Enum
class BaseResource(ModelResource):
class Meta:
read_only_fields = ['create_date', 'update_date']
class Schema:
create_date = fields.DateTimeString()
update_date = fields.DateTimeString()
class Location(Enum):
ARCHIVE_ONLY = 1
INSTANCES_ONLY = 2
BOTH = 3
class ArchiveManager(SQLAlchemyManager):
def _query(self, source=Location.INSTANCES_ONLY):
query = super(ArchiveManager, self)._query()
if source == Location.BOTH:
return query
elif source == Location.ARCHIVE_ONLY:
return query.filter(getattr(self.model, 'is_archived') == True)
else:
return query.filter(getattr(self.model, 'is_archived') == False)
def instances(self, where=None, sort=None, source=Location.INSTANCES_ONLY):
query = self._query(source)
if where:
expressions = [self._expression_for_condition(condition) for condition in where]
query = self._query_filter(query, self._and_expression(expressions))
if sort:
query = self._query_order_by(query, sort)
return query
def archive_instances(self, page, per_page, where=None, sort=None):
return self.instances(where=where, sort=sort, source=Location.ARCHIVE_ONLY).paginate(page=page, per_page=per_page)
def read(self, id, source=Location.INSTANCES_ONLY):
query = self._query(source)
if query is None:
raise ItemNotFound(self.resource, id=id)
return self._query_filter_by_id(query, id)
class ArchivingResource(BaseResource):
class Meta:
manager = ArchiveManager
exclude_routes = ['destroy'] # we're using rel="archive" instead.
class Schema(BaseResource.Schema):
is_archived = fields.Boolean(io='r')
@Route.GET('/<int:id>', rel="self", attribute="instance")
def read(self, id) -> fields.Inline('self'):
return self.manager.read(id, source=Location.BOTH)
@read.PATCH(rel="update")
def update(self, properties, id):
item = self.manager.read(id, source=Location.INSTANCES_ONLY)
updated_item = self.manager.update(item, properties)
return updated_item
update.response_schema = update.request_schema = fields.Inline('self', patchable=True)
@update.DELETE(rel="archive")
def destroy(self, id):
item = self.manager.read(id, source=Location.INSTANCES_ONLY)
self.manager.update(item, {"is_archived": True})
return None, 204
@Route.GET("/archive")
def archive_instances(self, **kwargs):
return self.manager.archive_instances(**kwargs)
archive_instances.request_schema = archive_instances.response_schema = Instances()
@Route.GET('/archive/<int:id>', rel="readArchived")
def read_archive(self, id) -> fields.Inline('self'):
return self.manager.read(id, source=Location.ARCHIVE_ONLY)
@Route.POST('/archive/<int:id>/restore', rel="restoreFromArchive")
def restore_from_archive(self, id) -> fields.Inline('self'):
item = self.manager.read(id, source=Location.ARCHIVE_ONLY)
return self.manager.update(item, {"is_archived": False})
class Base(object):
id = Column(Integer, primary_key=True, autoincrement=True)
create_date = Column(DateTime(timezone=True), server_default=func.now())
update_date = Column(DateTime(timezone=True), onupdate=func.now())
is_archived = Column(Boolean, default=False)
Base = declarative_base(cls=Base)
class User(Base):
__tablename__ = 'users'
name = Column(String(), nullable=True)
class UserResource(ArchivingResource):
class Meta(ArchivingResource.Meta):
model = User
natural_key = ('organization_id', 'foreign_id')
#write_only_fields = ['organization_id']
class Schema(ArchivingResource.Schema):
name = fields.String()
app.api.add_resource(UserResource)
Doing such filters are raising errors: /users?where={"create_date": {"$gt": "2018-06-10T14:56:15-05:00"}} /users/archive?where={"create_date": {"$gt": "2018-06-10T14:56:15-05:00"}}
I get: ValidationError {'$gt': '2018-06-10T14:56:15-05:00'} is not valid under any of the given schemas
Does /users?where={"create_date": {"$gt": "2018-06-10T19:56:15Z"}}
work?
@lyschoening Actually, that query doesn't work.
It seems the inheritance of the Meta
is not picking parent attributes.
create_date
and update_date
are not exposed for resources which inherit from ArchivingResource based on this definition:
class BaseResource(ModelResource):
class Meta:
read_only_fields = ['create_date', 'update_date']
class Schema:
create_date = fields.DateTimeString()
update_date = fields.DateTimeString()
class ArchivingResource(BaseResource):
class Meta(BaseResource.Meta):
manager = ArchiveManager
exclude_routes = ['destroy'] # we're using rel="archive" instead.
class Schema(BaseResource.Schema):
is_archived = fields.Boolean(io='r')
@matdrapeau Have you tried just class Meta:
and class Schema:
? Sorry, I did not spot that before. There should be no need to subclass those classes in the way you did.
@lyschoening no, same error as well without subclassing