art1415926535 / graphene-sqlalchemy-filter Goto Github PK
View Code? Open in Web Editor NEWFilters for Graphene SQLAlchemy integration
Home Page: https://pypi.org/project/graphene-sqlalchemy-filter/
License: MIT License
Filters for Graphene SQLAlchemy integration
Home Page: https://pypi.org/project/graphene-sqlalchemy-filter/
License: MIT License
I tried using the FilterSet
Class to create a filter on a field defined by a hybrid_property
in my sqlalchemy model, but it seems to have no effect. Graphene-Sqlalchemy does resolve the field on the type, but the filters
argument does not accept the hybrid_property
field I defined. I tried both the shortcut [...]
as well as explicit filter types but neither worked. Is this supported?
Here's an example (overly simplified for clarity):
models.py
class Post(db.Model):
__tablename__ = "projects"
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
@hybrid_property
def status(self):
return "Submitted"
filters.py
class PostFilter(FilterSet):
class Meta:
model = Post
fields = {
'status': ["eq", "in"]
}
class CustomFilter(FilterableConnectionField):
filters = {
Post: PostFilter(),
}
schema.py
class Post(SQLAlchemyObjectType):
class Meta:
model = PostModel
interfaces = (Node,)
connection_field_factory = CustomFilter.factory
connection_class = CountableConnection
Running this query:
query {
allPosts (filters: {status: "Submitted"}) {
edges {
node {
status
}
}
}
}
Returns:
{
"errors": [
{
"message": "Argument \"filters\" has invalid value {status: \"Submitted\"}.\nIn field \"status\": Unknown field.",
"locations": [
{
"line": 2,
"column": 25
}
]
}
]
}
I have a requirement to expose the actual id of the table back to the user. By default, id will be converted to graphql node id and the only way around is to create a synonym something like this in the model definition.
from sqlalchemy.orm import synonym
.
.
.
class SomeModel(Base):
__tablename__ = 'changelog'
id = Column(BigInteger, primary_key=True)
db_id = synonym('id)
Looks like that is not supported in graphene-sqllachemy-filter yet. (I'm using FilterableConnectionField)
Is it possible to pass a filter as a query parameter?
That is defining something like:
query($filters: Filter!){ ... }
And pass a dictionary to it (a.k.a. assign it to $filters) ? What type would Filter
be?
I have a field named type
and adding that in filterset fields give the following error to when creating the schema.
Exception has occurred: AttributeError
type object 'function' has no attribute 'name'
eg:
class SampleFilter(FilterSet):
class Meta:
model = SampleModel
fields = {
'name': [...],
'type': [...],
}
class Query(graphene.ObjectType):
node = graphene.relay.Node.Field()
all_samples = FilterableConnectionField(SampleSchemaObject.connection, filters=SampleFilter())
schema = graphene.Schema(query=Query)
It would be very helpful if we could do something like this, in order to automatically define filters for all fields and all operators:
class UserFilter(BaseFilter):
class Meta:
model = User
fields = [...]
Are there already opinions or solutions for this that I missed?
Is it possible to do something like the following, which allows filtering of addresses by user and filtering of users by their addresses. This code doesn't work because at the time the line address = AddressFilter()
is executed, the class AddressFilter
hasn't been defined.
class UserFilter(graphene_sqlalchemy_filter.FilterSet):
address = AddressFilter()
@classmethod
def address_filter(cls, info, query, value:
return cls.address.filter(info, query, value).join(db.Address), None
class Meta:
model = db.User
fields = {"text": [...], "strong": ["eq", "ne"]}
class AddressFilter(graphene_sqlalchemy_filter.FilterSet):
user = UserFilter()
@classmethod
def user_filter(cls, info, query, value):
return cls.user.filter(info, query, value).join(db.User), None
class Meta:
model = db.Address
fields = {"text": [...], "strong": [...],}
Maybe this is impossible because it would cause an infinite loop somewhere.
I've also tried adding UserFilter.address = AddressFilter()
at the bottom of the file, but although it doesn't throw any errors, it also doesn't work.
Hey Artem,
In issue #6 we also discussed that your syntax for creating FilterableConnectionField
s requires argument filters=
:
class ModelAFilter(FilterSet):
# ...
class ModelA(ObjectType):
Meta:
model = ModelAModel
# ...
class RootQuery(graphene.ObjectType):
something = FilterableConnectionField('ModelA', filters=ModelAFilter()) # <---
Could you somehow make it so that the ModelAFilter is specified directly inside ModelA or it's meta class, so that one does not have to manually pass the filters=
option when creating a field?
Thanks!
Since 1.11.2, im getting the following errors: ModuleNotFoundError: No module named 'sqlalchemy.ext.declarative.clsregistry'
I think it might be due to the dependency on my project. Is there a way to fix this on the library side?
Since the dataset is very large in my case, I want to have a feature to limit the size of a response dataset. For example, I want to make a filter field like timestamp
required. Is this a correct way?
Thanks for your great works!
How can I submit a token in a query and intercept to verify that the token is valid before performing the data search?
At this line in arguments always passed and_ function
First of all thanks for the awesome library! :)
I have a system with this sort of hierarchy:
Chapter.py
class Chapter(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String, nullable=False)
chapter_id = db.Column(ForeignKey('go_tab_chapters.id'))
sub_chapters = relationship('Chapter', backref=backref('chapter', remote_side=[id]),
primaryjoin=id == chapter_id)
checklists = relationship(Checklist, backref=backref('chapter'), uselist=True)
Checklist.py
class Checklist(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String, nullable=False)
chapter_id = db.Column(ForeignKey('go_tab_chapters.id'))
This is my GraphQL entities:
class ChapterFilter(FilterSet):
class Meta:
model = Chapter
fields = {'name': [...]}
class ChecklistFilter(FilterSet):
class Meta:
model = Checklist
fields = {
'name': [...]
}
class CustomField(FilterableConnectionField):
filters = {
Chapter: ChapterFilter(),
Checklist: ChecklistFilter()
}
class ChapterNode(SQLAlchemyObjectType):
class Meta:
model = Chapter
interfaces = (graphene.relay.Node,)
connection_field_factory = CustomField.factory
class ChapterConnection(Connection):
class Meta:
node = ChapterNode
class ChecklistNode(SQLAlchemyObjectType):
class Meta:
model = Checklist
interfaces = (graphene.relay.Node,)
connection_field_factory = CustomField.factory
class ChecklistConnection(Connection):
class Meta:
node = ChecklistNode
When I'm trying to run the following query:
{
chapters (filters:{
name: "abc"
}){
edges{
node{
name
checklists (filters:{
name: "abc"
}){
edges{
node{
name
}
}
}
subChapters{
edges{
node{
name
}
}
}
}
}
}
}
I get the following error:
graphql.error.located_error.GraphQLLocatedError: Can't construct a join from Mapper|Chapter|chapters to Mapper|Chapter|chapters, they are the same entity
When I comment the following line the query works but not the nested filter:
class ChapterNode(SQLAlchemyObjectType):
class Meta:
model = Chapter
interfaces = (graphene.relay.Node,)
# connection_field_factory = CustomField.factory
@art1415926535 , Can you please help?
Many thanks!
Something like this doesn't work as you would expect, only the last and
clause is taken:
{
cuentas(first: 10, filters: {and: {cuentaIlike: "%co%" cuentaIlike: "%pa%"}}) {
edges {
node {
idCuenta
cuenta
}
}
}
}
You can get it to work with this hack:
{
cuentas(first: 10, filters: {and: {cuentaIlike: "%co%" and: {cuentaIlike: "%pa%"}}}) {
edges {
node {
idCuenta
cuenta
}
}
}
}
More a question than an issue.
I'm noticing that rendered MySQL queries are sometimes un-optimized, e.g.
SELECT table_1.id AS table_1_id, anon_1.id AS anon_1_id, anon_1.first_name AS anon_1_first_name, anon_1.last_name AS anon_1_last_name, anon_1.email AS anon_1_email
FROM table_1 INNER JOIN (SELECT cglookup_persons.id AS id, cglookup_persons.first_name AS first_name, cglookup_persons.last_name AS last_name, cglookup_persons.email AS email
FROM cglookup_persons ORDER BY cglookup_persons.id ASC) AS anon_1 ON anon_1.id = table_1.person
WHERE table_1.id IN (2199927)
the nested query causes the entire table to be loaded into a hash table to be first sorted only then to be completely excluded by the join.
Skipping the ORDER BY
would be enough to greatly reduce the execution time, something like
SELECT table_1.id AS table_1_id, anon_1.id AS anon_1_id, anon_1.first_name AS anon_1_first_name, anon_1.last_name AS anon_1_last_name, anon_1.email AS anon_1_email
FROM table_1 INNER JOIN cglookup_persons AS anon_1 ON anon_1.id = table_1.person
WHERE table_1.id IN (2199927)
is this achievable in any way? I guess is related to the sorting, so I'm going to try that, though I was wondering if you have some experience with it to avoid side effects.
Hi,
I followed the instructions to set up the nested filters. They seem to work, but the sorting does not.
Are there additional steps required to get the sorting to work?
Thanks!
Jonathan
Hello,
The module is great. I have it running successfully when fields are defined at the top of the tree, like you show in the example:
class Query(ObjectType):
all_users = CustomField(UserConnection, where=UserFilter())
However, graphene-sqlalchemy
automatically finds and wraps all relationships between ORM models into GraphQL connections.
How did you envision that the benefits of this module could be applied to all those connections automatically?
Thanks.
Seeing the following error after updating package version from 1.11.1
to 1.12.0
:
my_code/graphql/filters/specimen.py:7: in <module>
class SpecimenFilter(FilterSet):
.tox/py38/lib/python3.8/site-packages/graphene/utils/subclass_with_meta.py:52: in __init_subclass__
super_class.__init_subclass_with_meta__(**options)
.tox/py38/lib/python3.8/site-packages/graphene_sqlalchemy_filter/filters.py:292: in __init_subclass_with_meta__
filters_fields = cls._generate_default_filters(model, fields)
.tox/py38/lib/python3.8/site-packages/graphene_sqlalchemy_filter/filters.py:511: in _generate_default_filters
model_fields = cls._get_model_fields_data(model, field_filters.keys())
.tox/py38/lib/python3.8/site-packages/graphene_sqlalchemy_filter/filters.py:609: in _get_model_fields_data
column = attr.columns[0]
.tox/py38/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py:977: in __getattr__
return self._fallback_getattr(key)
.tox/py38/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py:951: in _fallback_getattr
raise AttributeError(key)
E AttributeError: columns
specimen.py
looks like:
class SpecimenFilter(FilterSet):
class Meta:
model = SpecimenModel
fields = {
"type": ["eq", "ne", "in", "not_in"],
"status": ["eq", "ne"],
"group": ["eq"],
"identifier": ["eq", "ne", "like", "ilike", "contains"],
"created_at": ["gt", "lt", "gte", "lte"],
"updated_at": ["gt", "lt", "gte", "lte"],
}
is_ready = graphene.Boolean()
@staticmethod
def is_ready_filter(info, query, value):
ready = SpecimenModel.is_ready # this is a hybrid_property that performs some joins
return ready if value else not ready
It appears this commit introduces the issue: 2562ad7
I am still investigating. Wanted to post the issue early in case this is a regression from the most-recent release. I will update with more when/if I gain more insight.
Did I miss a breaking API change or other deprecation?
Thanks!
Hey thank you for this great lib and it solves a lot of my problems.
In my use case, I don't really need Relay and the Relay kinda makes the query confusing as we need to add edges
and node
etc.
I'd like to keep the normal GraphQL query syntax but also have the auto-generated filters.
Is there a way to accomplish this? Do we have a FilterableField
instead of FilterableConnectionField
?
Thank you!
Is it possible to change the syntax of the filter to: filters: {[column_name]: {[operator]: [value_name]}}
?
Hi, is there a way to do custom filtering on the results? I want to filter out results that the user doesn't not have access to so it can't be part of the initial query.
Let's say we have 2 models with a relationship between them, such as:
class ModelA:
modelb_id = db.Column(db.BigInteger(), db.ForeignKey('modelb.id'), nullable=True)
modelb = db.relationship('ModelB')
class ModelB:
name = db.Column(db.Text, ...)
...
Now, when the filter module wraps ModelA, it will automatically make the following available through GraphQL:
modela(...) {
modelbId
modelb {
id
name
}
}
However, the value in modelbId
will be a plain integer, rather than a global/hashed GraphQL ID like obtained when querying modelb { id }
.
Based on that, I have two questions:
Is it possible to add built-in support so that all the cases like this are automatically recognized and return GraphQL IDs?
If it is not possible or not accepted to add this as built-in behavior to the filter module, how would one do this manually in their project?
Thanks!
Maybe I am missing something obvious, but how would I go about writing a contains filter for postgres?
This is the class method because I am modifying the query.
@classmethod
def in_old_ids_filter(cls, info, query, value):
has_id = cls.aliased(query, Model, name='in_old_ids')
query = query.filter(Model.old_ids.contains(value)) # postgres sqlalchemy
return query, ???
Thanks!
In my models, I renamed the column id
to be request_id
class Request(Base):
__tablename__ = "requests"
request_id = Column("id", String, primary_key=True)
datasets = relationship("Dataset")
The filter gave me this error "message": "'Request' object has no attribute 'id'",
when I queried datasets
. But if I used id=Column(String, primary_key=True)
, it worked. Any idea?
Hi, would it be possible to include mssql types as well as potsgreSQL?When my data is in MS SQL database it throws an error using declerativebase in SQL alchemy if I try to make a filter on variable that isn't converted into SQLalchemy type. Here is the error:
File "\venv\lib\site-packages\graphene_sqlalchemy_filter\filters.py", line 359, in _generate_default_filters expressions = filters_map[column_type.__class__].copy() KeyError: <class 'sqlalchemy.sql.sqltypes.NVARCHAR'>
Is it possible to create a filter using properties from a relationship to a model? Say for the models:
from database import Base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, backref
class Foo(Base):
__tablename__ = 'foo'
f_id = Column(Integer, primary_key = True)
name = Column(String)
bar = relationship('Bar', backref='foo')
class Bar(Base):
__tablename__ = 'bar'
b_id = Column(Integer, primary_key = True)
number = Column(Int)
f_id = Column(Integer, ForeignKey('foo.f_id'))
I would like to create a filter that might emulate the following:
from graphene import Int
from graphene_sqlalchemy_filter import FilterSet
class FooFilter(FilterSet):
number = Int()
class Meta:
model = Foo
def number_filter(self, query, value):
return Foo.Bar.number == value
This doesn't work, but how would I go about to get similar functionality? Any help appreciated!
Hi, I'm currently only generating filters for columns -- is there a way to generate via Relationship so I can also filter by relationship?
Thank you.
Xu
How should I configure graphene-sqlalchemy-filter
to account for VARBINARY fields in a SQLAlchemy model?
I have no issues using graphene-sqlalchemy-filter
filtering on INTEGER columns. With VARBINARY defined columns, I can filter using numeric only strings with these caveats.
{
"errors": [
{
"message": "Extra data: line 1 column 6 (char 5)"
}
]
}
You can view my code here where I'm attempting to filter the PairXlate
table on key
(VARBINARY) and idx_pair_xlate_group
(BIGINT).
: https://github.com/palisadoes/pattoo/tree/753885eb4dfa72c525425a29c98e5fd6ef6fb8ff/pattoo/db
The filtration library seems very close to what's needed for authorization logic. We have an incoming JWT token and would like to do something like adding 'implicit' filters (sometimes with joins) on most objects based on whether the userid (or, for joins, the userid in a related object) is the same as what's in the JWT.
Is there a good way to write filters and then have them triggered even when the graphql query did not include a filter, i.e., to mark certain kinds of filters as 'implicit' and use those for authorization?
I'm new to both the library and graphql. I've looked around a bit here & elsewhere and seen a bit of discussion of auth, but so far I can't figure out whether this is a reasonable direction to head.
In some cases when calling a query directly with schema.execute(query_string)
, I'll get some warning / error message about NoneType
. However, when using a flask app instead, I don't receive any error messages on the server side nor the client side.
from sqlalchemy import create_engine, Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine("sqlite:///:memory:", echo=True)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
class Song(Base):
__tablename__ = 'songs'
song_id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
tags = relationship('Tag',
secondary='song_tag_table',
backref='songs')
class Tag(Base):
__tablename__ = 'tags'
tag_id = Column(Integer, primary_key=True)
name = Column(String)
class SongTagTable(Base):
__tablename__ = 'song_tag_table'
id = Column(Integer, primary_key=True)
song_id = Column(Integer, ForeignKey('songs.song_id'))
tag_id = Column(Integer, ForeignKey('tags.tag_id'))
Base.metadata.create_all(engine)
# ==========
from graphene import ObjectType, Schema
from graphene.relay import Connection, Node
from graphene_sqlalchemy import SQLAlchemyObjectType
from graphene_sqlalchemy_filter import FilterableConnectionField, FilterSet
class SongFilter(FilterSet):
class Meta:
model = Song
fields = {'song_id': ['eq', 'ne', 'in']}
class TagFilter(FilterSet):
class Meta:
model = Tag
fields = {'tag_id': ['eq', 'ne', 'in']}
class CustomField(FilterableConnectionField):
filters = {
Song: SongFilter(),
Tag: TagFilter()
}
class SongNode(SQLAlchemyObjectType):
class Meta:
model = Song
interfaces = (Node,)
connection_field_factory = CustomField.factory
class TagNode(SQLAlchemyObjectType):
class Meta:
model = Tag
interfaces = (Node,)
connection_field_factory = CustomField.factory
class SongConnection(Connection):
class Meta:
node = SongNode
class TagConnection(Connection):
class Meta:
node = TagNode
class Query(ObjectType):
all_songs = CustomField(SongConnection)
all_tags = CustomField(TagConnection)
schema = Schema(query=Query)
# ==========
jpop = Tag(name='jpop')
subarashi = Song(name='素晴らしい日々')
subarashi.tags.append(jpop)
db_session.add(subarashi)
fool_in_tank = Song(name='水槽のフール')
fool_in_tank.tags.append(jpop)
db_session.add(fool_in_tank)
despacito = Song(name='despacito')
db_session.add(despacito)
db_session.commit()
# ==========
query_string = """
insert test query here
"""
res = schema.execute(query_string)
print(res)
query_string = """
query {
allSongs {
edges {
node {
name
}
}
}
}
"""
response (normal):
{'data': {'allSongs': {'edges': [{'node': {'name': '素晴らしい日々'}}, {'node': {'name': '水槽のフール'}}, {'node': {'name': 'despacito'}}]}}}
query_string = """
query {
allSongs(filters: {songIdNe: 2}) {
edges {
node {
name
}
}
}
}
"""
response (normal):
{'data': {'allSongs': {'edges': [{'node': {'name': '素晴らしい日々'}}, {'node': {'name': 'despacito'}}]}}}
warning:
c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\filters.py:750: RuntimeWarning: Graphene-SQLAlchemy-Filter: info.context has an unsupported type <class 'NoneType'>. Now cls.aliased(info, ...) is not supported. Allowed types: dict and object with __dict__ attribute.
warnings.warn(msg, RuntimeWarning)
query_string = """
query {
allSongs {
edges {
node {
name
tags {
edges {
node {
name
}
}
}
}
}
}
}
"""
response:
{'errors': [{'message': "'NoneType' object has no attribute '_sqla_filter_dataloaders'", 'locations': [{'line': 7, 'column': 9}], 'path': ['allSongs', 'edges', 0, 'node', 'tags']}, {'message': "'NoneType' object has no attribute '_sqla_filter_dataloaders'", 'locations': [{'line': 7, 'column': 9}], 'path': ['allSongs', 'edges', 1, 'node', 'tags']}, {'message': "'NoneType' object has no attribute '_sqla_filter_dataloaders'", 'locations': [{'line': 7, 'column': 9}], 'path': ['allSongs', 'edges', 2, 'node', 'tags']}], 'data': {'allSongs': {'edges': [{'node': {'name': '素晴らしい日々', 'tags': None}}, {'node': {'name': '水槽のフール', 'tags': None}}, {'node': {'name': 'despacito', 'tags': None}}]}}}
error:
An error occurred while resolving field SongNode.tags
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 318, in _get_or_create_data_loader
setattr(info.context, cls.dataloaders_field, data_loaders)
AttributeError: 'NoneType' object has no attribute '_sqla_filter_dataloaders'
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 318, in _get_or_create_data_loader
setattr(info.context, cls.dataloaders_field, data_loaders)
graphql.error.located_error.GraphQLLocatedError: 'NoneType' object has no attribute '_sqla_filter_dataloaders'
An error occurred while resolving field SongNode.tags
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 318, in _get_or_create_data_loader
setattr(info.context, cls.dataloaders_field, data_loaders)
AttributeError: 'NoneType' object has no attribute '_sqla_filter_dataloaders'
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 318, in _get_or_create_data_loader
setattr(info.context, cls.dataloaders_field, data_loaders)
graphql.error.located_error.GraphQLLocatedError: 'NoneType' object has no attribute '_sqla_filter_dataloaders'
An error occurred while resolving field SongNode.tags
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 318, in _get_or_create_data_loader
setattr(info.context, cls.dataloaders_field, data_loaders)
AttributeError: 'NoneType' object has no attribute '_sqla_filter_dataloaders'
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 318, in _get_or_create_data_loader
setattr(info.context, cls.dataloaders_field, data_loaders)
graphql.error.located_error.GraphQLLocatedError: 'NoneType' object has no attribute '_sqla_filter_dataloaders'
library versions:
python: 3.8.0
sqlalchemy: 1.3.20
graphene: 2.1.8
graphene_sqlalchemy: 2.3.0
graphene_sqlalchemy_filter: 1.12.1
I'm new to both sqlalchemy and graphql, so hopefully I didn't make any trivial mistakes. Thanks!
Hey,
I have a query like this:
someObjects(filters: {and: [{status: "DONE"}]}) {
totalCount
}
This is producing totalCount
by retrieving all this in Python and doing a len()
on it.
What's the suggested way to make this be a DB query using count
?
(If the only solution is to rewrite the whole query in a different way or to provide my own/custom field which does count()
, that's a fine too.)
Hi,
What's the syntax for filtering datetime by range?
Obs.: using range filter.
Hi
I'm trying to use Enum in filter but get a problem
models
class IssueCommentType(Enum):
default = 'Not defined'
author = 'Response from author'
class IssueComment(db.Model):
comment_id = db.Column(db.INT, primary_key=True)
issue_id = db.Column(db.ForeignKey('issue.issue_id'), nullable=False)
comment = db.Column(db.TEXT, nullable=False)
date = db.Column(db.DateTime, nullable=False)
type = db.Column(db.Enum(IssueCommentType), nullable=False, default=IssueCommentType.default)
filter
class IssueCommentFilter(FilterSet):
class Meta:
model = IssueComment
fields = {
'type': ['eq', 'ne'],
}
class MyFilterableConnectionField(FilterableConnectionField):
filters = {
Issue: IssueFilter(),
IssueComment: IssueCommentFilter(),
IssueExtraFields: ExtraFieldsFilter(),
}
query
{
issues(first: 10) {
totalCount
edges {
node {
comments(filters: {type:AUTHOR}) {
edges {
node {
comment
date
type
}
}
}
}
}
}
}
error
graphql.error.located_error.GraphQLLocatedError: (psycopg2.errors.InvalidTextRepresentation)
ERROR: incorrect value for enum issuecommenttype: "Response from author"
LINE 4: WHERE issue_comment.type = 'Response from author') AS anon_1...
^
enum in database created with enum names but filter trying to use enum values
Hi,
I am getting this error with FilterableConnectionField
, however with original SQLAlchemyConnectionField
it works. I have tried with my own model as well as with dummy User model used in the example. Using Flask.
An error occurred while resolving field Query.allPreds
Traceback (most recent call last):
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphql/execution/executor.py", line 450, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphql/execution/executors/sync.py", line 16, in execute
return fn(*args, **kwargs)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy/fields.py", line 74, in connection_resolver
return on_resolve(resolved)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy/fields.py", line 47, in resolve_connection
resolved = cls.get_query(model, info, **args)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy_filter/connection_field.py", line 32, in get_query
query = filter_set.filter(info, query, request_filters)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy_filter/filters.py", line 446, in filter
info.context[cls._filter_aliases] = {}
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/werkzeug/local.py", line 351, in __setitem__
self._get_current_object()[key] = value
TypeError: 'Request' object does not support item assignment
Traceback (most recent call last):
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphql/execution/executor.py", line 450, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphql/execution/executors/sync.py", line 16, in execute
return fn(*args, **kwargs)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy/fields.py", line 74, in connection_resolver
return on_resolve(resolved)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy/fields.py", line 47, in resolve_connection
resolved = cls.get_query(model, info, **args)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy_filter/connection_field.py", line 32, in get_query
query = filter_set.filter(info, query, request_filters)
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/graphene_sqlalchemy_filter/filters.py", line 446, in filter
info.context[cls._filter_aliases] = {}
File "/home/datas/predictions-api/venv/lib/python3.6/site-packages/werkzeug/local.py", line 351, in __setitem__
self._get_current_object()[key] = value
graphql.error.located_error.GraphQLLocatedError: 'Request' object does not support item assignment
query
{ allPreds (filters:{shopId: 134}) { edges { node { id } } } }
Hi
I am trying to filter on an Enum field, but if I add one to the filter I get:
File "/opt/venv/lib/python3.8/site-packages/graphene_sqlalchemy_filter/filters.py", line 531, in _generate_default_filters
fields = cls._generate_filter_fields(
File "/opt/venv/lib/python3.8/site-packages/graphene_sqlalchemy_filter/filters.py", line 610, in _generate_filter_fields
filter_field = field_type(description=doc)
TypeError: function() missing required argument 'code' (pos 1)
Do you have any ideas how to fix this?
{
allUsers(filters: {isActive: 1}) {
edges {
node {
id
}
}
}
allGroups {
edges {
node {
users(filters: {isActive: 1}) {
edges {
node {
name
}
}
}
}
}
}
}
model:
class TmTeamsUsers(db.Model):
"""Model for 'tmteamsusers'"""
__tablename__ = 'tmteamsusers'
teamid = db.Column('teamid', INTEGER(11), primary_key=True, nullable=False)
userid = db.Column('userid', INTEGER(11), primary_key=True, nullable=False)
minimizeWindow = db.Column('minimizeWindow', SMALLINT(1), nullable=False)
isAdministrator = db.Column('isAdministrator', SMALLINT(1), nullable=False)
intranetid = db.Column('intranetid', INTEGER(11), nullable=False)
isActive = db.Column('isActive', SMALLINT(1, unsigned=True), nullable=False)
error:
{
"errors": [
{
"message": "Cannot query field \"users\" on type \"GroupNode\". Did you mean \"userid\"?",
"locations": [
{
"line": 12,
"column": 9
}
]
}
]
}
What do I have to add to my model in order to get this working?
user = relationship('User', foreign_keys=[userid], primaryjoin='User.id == TmTeamsUsers.userid')
Does not work for example.
Howdy,
First things first thank you for the amazing library.
It seems that the model loader's get query method incorrectly adds order_by arguments to the generated sqlalchemy query. Order by gets added here to the subquery which makes sense because they are relevant to the table that subquery deals with. However in cases where an association table is used (have not checked for typical relationships) the order by is not respected because the subquery result is joined again back to parent table.
I was able to solve the problem by patching the aforementioned function and adding a section that translates the order by arguments to the aliased model so that I could add them outside the subquery:
...
# Translate sortEnums of the original model to the aliased one
aliased_sort = []
for col in sort:
# Use direction present in the original name to pick a SQLAlchemy direction
direction_func = asc if col.lower().endswith("asc") else desc
# Get everything left of the first "_"
name = "_".join(col.lower().split("_")[:-1])
# Derive the aliased column from the extracted name of the original
alias_column = getattr(aliased_model, name)
# Combine
aliased_sortable = direction_func(alias_column)
aliased_sort.append(aliased_sortable)
query = (
get_query(self.parent_model, self.info.context)
.join(aliased_model, self.relation)
.options(
contains_eager(self.relation, alias=aliased_model),
Load(self.parent_model).load_only(self.parent_model_pk_field),
)
.order_by(
*(col for col in aliased_sort)
) # Add an ordering by the alias table outside the join so order is respected
)
return query
...
I recognize this to be a bit on the hacky side and I haven't tested it extensively but I'm interested in feedback. I'd be happy to clean it up and submit a PR to fix if interested.
Hello there.
Thanks for creating this library, it is helping me a lot in my current project. I saw no other direct way to contact you so I decided to post this as an issue, sorry if this is inappropriate.
I noticed in the readme under features the following line:
pagination (first/after, last/before) are performed by python (keep this in mind when working with large amounts of data)
First I was discouraged as I will most likely be working on quite large amounts of data at some point in the future (potentially millions of rows). I looked through the repo trying to find where pagination is handled but was not able to. After some more digging, I enabled debug logging for sqlalchemy and noticed that limit and offset is sent to the database.
SELECT auth."user".id AS auth_user_id, auth."user".email AS auth_user_email, auth."user".password AS auth_user_password, auth."user".lastmodified AS auth_user_lastmodified, auth."user"."roleId" AS "auth_user_roleId"
FROM auth."user" ORDER BY auth."user".lastmodified DESC
LIMIT %(param_1)s OFFSET %(param_2)s
Does your original statement still hold true or is this graphene actually handling pagination via postgres? Thanks once again.
If I have a query written like:
query myQuery ($myFieldFilter: ID) {
myType (filters: {myField: $myFieldFilter}) {
myField
}
If I pass the parameter $myFieldFilter
as null
, I would like to essentially ignore the filtering entirely. This would allow me on the front end to not have to modify the structure of the query itself. It seems there is already a way to explicitly find null
values with the filter type: myFieldIsNull
. I was able to achieve this by modifying the function:
def _eq_filter(field: 'Column', value: 'Any') -> 'Any':
if value is None:
return True # ignore filter
column_type = field.type
if isinstance(column_type, postgresql.ARRAY):
value = cast(value, column_type)
return field == value
This is perhaps not the desired behavior of the filter in general so perhaps a setting in the Meta
class to toggle the functionality would be desirable. Not sure if this is functionality other people would find useful, just wanted to share my experience.
membership = cls.aliased(query, Membership, name='is_moderator')
GraphQLLocatedError: 'Query' object has no attribute '_join_entities'
Since SQLALchemy 1.4, Query
._join_entities
method doesn't exist any more. This method is used in the implementation of FilterSet
._aliases_from_query
.
When I try to define a filter using a join, following the instructions in the documentation, the exception above is thrown.
The UnsortedSQLAlchemyConnectionField.resolve_connection function throws the following error when it tries to resolve relationship fields that are Sets instead of lists (defined using SQLAlchemy's "collection_class=set" on the relationship).
ERROR: Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/promise/promise.py", line 87, in try_catch
return (handler(*args, **kwargs), None)
File "/usr/local/lib/python3.8/site-packages/graphene_sqlalchemy/fields.py", line 56, in resolve_connection
connection = connection_from_list_slice(
File "/usr/local/lib/python3.8/site-packages/graphql_relay/connection/arrayconnection.py", line 79, in connection_from_list_slice
_slice = list_slice[
graphql.error.located_error.GraphQLLocatedError: 'InstrumentedSet' object is not subscriptable
This can be worked around for fields in the GraphQL model classes by adding a resolver function that converts the sets to lists, but nested filtered connection fields use the UnsortedSQLAlchemyConnectionField.resolve_connection function by default, which doesn't seem to be easy to override.
So I have 2 records in schema Foo:
id: 1, key: 'foo'
id: 2, key: 'foobar'
if I run the below command:
query { Foo(filters: { key_like: "%foo%", and: [{ id: "1" }] }) { id key } }
it will return:
{ "data": { "Foo": [ { "id": "1", "key": "foo" } ] } }
, which is expected, as both records' key like foo, but only record 1 has the id 1, so only the record 1 was returned;
but if I run the below command:
query { Foo(filters: { key_like: "%foo%", or: [{ id: "2" }] }) { id key } }
it will ONLY return:
{ "data": { "Foo": [ { "id": "2", "key": "foobar" } ] } }
Shouldn't both records got returned?
I'm not using relay and I'm using the example code (w/o relay) you provide the other day to build the filter set.
how we can calculate the average based on field and filters?
Hi! I'm using this library with Fast API and experiencing an issue with filters with joins. Sometimes this piece of code returns None:
@classmethod
def _aliases_from_query(cls, query: Query) -> 'Dict[str, _MapperEntity]':
"""
Get aliases from SQLAlchemy query.
Args:
query: SQLAlchemy query.
Returns:
Dictionary of model aliases.
"""
aliases = {
(mapper._target, mapper.name): mapper.entity
for mapper in query._join_entities
}
return aliases
mapper.entity
is None from time to time. This is because it uses weakref and entity object gets garbage collected or something like that I didn't dig that much. When I try to join the table once more sqlalchemy complains that it's already joined. Maybe you @art1415926535 could give some advice on how to fix that? Thanks
the query generated by subquery when using filters unambiguously labeling columns resulting in an ambiguous column exception.
long story short, I have a polymorphic database, so id is shared between a base class and the filtered child class. that seems to be the root of the issue. after playing around for a while I found subquery.subquery() has a with_labels argument you can pass. setting that to True fixed the issue for me
e.g. connection_field.py line 250
aliased_model = aliased(self.model, subquery.subquery(with_labels=True))
Haven't managed to use variables with filters, is there a way to do so?
for instance I'd like to have sth like
query users($filter: UserFilter) { users(filters: $filter) { edges { node { id name } } } }
with variables:
{ "filter": { "name": "joe" } }
I just bumped into the ModelNotSupported
Exception after adding a second primary key to a model. (https://github.com/art1415926535/graphene-sqlalchemy-filter/blob/master/graphene_sqlalchemy_filter/connection_field.py#L195)
Is there any kind of approach recomended when bumping into this scenario?
sqlalchemy 1.4.0b1 was released recently, in many ways attempting to serve as a potential migration point for a more dramatic series of API changes currently planned for release 2.0 of SQLAlchemy
. The beta version can be installed by passing --pre
flag when installing the library, such as:
py -m pip install --pre sqlalchemy
See issue #38 for my test case, with the following changes:
using sqlalchemy version 1.4.0b1 instead of version 1.3.20
from flask import Flask
from flask_graphql import GraphQLView
app = Flask(__name__)
app.debug = True
app.add_url_rule(
'/graphql',
view_func=GraphQLView.as_view(
'graphql',
schema=schema,
graphiql=True # for having the GraphiQL interface
)
)
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
if __name__ == '__main__':
# for this to work in jupyter notebook
from werkzeug.serving import run_simple
run_simple('localhost', 9000, app)
query {
allSongs {
edges {
node {
name
tags {
edges {
node {
name
}
}
}
}
}
}
}
{
"errors": [
{
"message": "items",
"locations": [
{
"line": 6,
"column": 9
}
],
"path": [
"allSongs",
"edges",
0,
"node",
"tags"
]
},
{
"message": "items",
"locations": [
{
"line": 6,
"column": 9
}
],
"path": [
"allSongs",
"edges",
1,
"node",
"tags"
]
},
{
"message": "items",
"locations": [
{
"line": 6,
"column": 9
}
],
"path": [
"allSongs",
"edges",
2,
"node",
"tags"
]
}
],
"data": {
"allSongs": {
"edges": [
{
"node": {
"name": "素晴らしい日々",
"tags": null
}
},
{
"node": {
"name": "水槽のフール",
"tags": null
}
},
{
"node": {
"name": "despacito",
"tags": null
}
}
]
}
}
}
An error occurred while resolving field SongNode.tags
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 324, in _get_or_create_data_loader
current_data_loader: ModelLoader = data_loaders[data_loader_key]
KeyError: ('allSongs', 'edges', 'node', 'tags')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1104, in __getattr__
return self._index[key]
KeyError: 'items'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 326, in _get_or_create_data_loader
current_data_loader = ModelLoader(type(root), model, info, args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 137, in __init__
self.parent_model_pks: 'Tuple[str, ...]' = self._get_model_pks(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 197, in _get_model_pks
for name, c in inspection.inspect(model).columns.items()
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1106, in __getattr__
util.raise_(AttributeError(key), replace_context=err)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\util\compat.py", line 180, in raise_
raise exception
AttributeError: items
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 326, in _get_or_create_data_loader
current_data_loader = ModelLoader(type(root), model, info, args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 137, in __init__
self.parent_model_pks: 'Tuple[str, ...]' = self._get_model_pks(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 197, in _get_model_pks
for name, c in inspection.inspect(model).columns.items()
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1106, in __getattr__
util.raise_(AttributeError(key), replace_context=err)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\util\compat.py", line 180, in raise_
raise exception
graphql.error.located_error.GraphQLLocatedError: items
An error occurred while resolving field SongNode.tags
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 324, in _get_or_create_data_loader
current_data_loader: ModelLoader = data_loaders[data_loader_key]
KeyError: ('allSongs', 'edges', 'node', 'tags')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1104, in __getattr__
return self._index[key]
KeyError: 'items'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 326, in _get_or_create_data_loader
current_data_loader = ModelLoader(type(root), model, info, args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 137, in __init__
self.parent_model_pks: 'Tuple[str, ...]' = self._get_model_pks(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 197, in _get_model_pks
for name, c in inspection.inspect(model).columns.items()
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1106, in __getattr__
util.raise_(AttributeError(key), replace_context=err)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\util\compat.py", line 180, in raise_
raise exception
AttributeError: items
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 326, in _get_or_create_data_loader
current_data_loader = ModelLoader(type(root), model, info, args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 137, in __init__
self.parent_model_pks: 'Tuple[str, ...]' = self._get_model_pks(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 197, in _get_model_pks
for name, c in inspection.inspect(model).columns.items()
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1106, in __getattr__
util.raise_(AttributeError(key), replace_context=err)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\util\compat.py", line 180, in raise_
raise exception
graphql.error.located_error.GraphQLLocatedError: items
An error occurred while resolving field SongNode.tags
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 324, in _get_or_create_data_loader
current_data_loader: ModelLoader = data_loaders[data_loader_key]
KeyError: ('allSongs', 'edges', 'node', 'tags')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1104, in __getattr__
return self._index[key]
KeyError: 'items'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 326, in _get_or_create_data_loader
current_data_loader = ModelLoader(type(root), model, info, args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 137, in __init__
self.parent_model_pks: 'Tuple[str, ...]' = self._get_model_pks(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 197, in _get_model_pks
for name, c in inspection.inspect(model).columns.items()
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1106, in __getattr__
util.raise_(AttributeError(key), replace_context=err)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\util\compat.py", line 180, in raise_
raise exception
AttributeError: items
Traceback (most recent call last):
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executor.py", line 452, in resolve_or_error
return executor.execute(resolve_fn, source, info, **args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphql\execution\executors\sync.py", line 16, in execute
return fn(*args, **kwargs)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 356, in connection_resolver
data_loader: ModelLoader = cls._get_or_create_data_loader(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 326, in _get_or_create_data_loader
current_data_loader = ModelLoader(type(root), model, info, args)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 137, in __init__
self.parent_model_pks: 'Tuple[str, ...]' = self._get_model_pks(
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\graphene_sqlalchemy_filter\connection_field.py", line 197, in _get_model_pks
for name, c in inspection.inspect(model).columns.items()
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\sql\base.py", line 1106, in __getattr__
util.raise_(AttributeError(key), replace_context=err)
File "c:\users\geoffrey\appdata\local\programs\python\python38\lib\site-packages\sqlalchemy\util\compat.py", line 180, in raise_
raise exception
graphql.error.located_error.GraphQLLocatedError: items
I feel like this may be related to #38 but I'm not sure, opening a separate issue just in case.
For example
class UserFilter(FilterSet):
is_cool = graphene.Boolean()
@classmethod
async def is_cool_filter(cls, info, query, value):
returned_list= await async_func()
if value:
filter_ = query.id.in_(returned_list)
else:
filter_ = query.id.in_(None)
return query, filter_
I am having issues in implementing graphene-sqlalchemy-filter in nested graphQL query. It is working as expected with normal graphQL query but when implemented in nested query the filter seems to not work.
I have two models:
class GroupModel(Base):
__tablename__ = "groups"
id = Column(Integer, primary_key=True)
name = Column(Text, index=True)
tasks = relationship(
"TaskModel",
backref=backref("circle", lazy='bulk'),
lazy='bulk',
cascade="all, delete-orphan",
)
class TaskModel(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True)
group_id = Column(Integer, ForeignKey("groups.id"), nullable=False)
title = Column(Text, nullable=False)
done = Column(Boolean, nullable=False, index=True)
categories = Column(
Text,
default="General",
)
#The code for filtering :
class GroupTodoFilter(FilterSet):
class Meta:
model = TaskModel
fields = {
'title': ['eq'],
'done': ['eq'],
'categories': ['eq'],
}
class GroupFilterableConnectionField(FilterableConnectionField):
filters = {TaskModel: GroupTaskFilter()}
class TaskFilter(SQLAlchemyObjectType):
class Meta:
model = TaskModel
interfaces = (relay.Node, )
connection_field_factory = GroupFilterableConnectionField.factory
class TaskFilterConnection_1(Connection):
class Meta:
node = TaskFilter
class GroupFilterNode(SQLAlchemyObjectType):
class Meta:
model = GroupModel
interfaces = (relay.Node, )
connection_field_factory = GroupFilterableConnectionField.factory
class GroupFilterConnection(Connection):
class Meta:
node = GroupFilterNode
`
in schema:
all_task = GroupFilterableConnectionField(TaskFilterConnection_1)
all_group_filters = GroupFilterableConnectionField(
GroupFilterConnection)
filter_group = relay.Node.Field(GroupFilterNode)
Queries
query{
allGroupFilters{
edges{
node{
tasks(filters:{done:true}){
edges{
node{
id
groupId
categories
done
title
}
}
}
}
}
}
}
query{
allTask (filters:{done:false}){
edges{
node{
id
title
groupId
categories
done
}
}
}
}
query($id: ID!) {
filterGroup (id: $id) {
tasks (filters:
{categories:"Health"}
)
{
edges {
node {
id
group {
id
}
title
done
categories
}
}
}
}
}`
Task query is working alright but filterGroup and allFilterGroup query have no filtering affect.
First off, this is awesome! I'm still not 100% familiar with the intricacies of SQLAlchemy and it would have taken me a while to write something as complete as this library. Thanks!
I have a relatively simple setup.
Model:
class Transaction(Base):
# ...
memo = Column(Text)
# ...
Filter:
class TransactionFilter(FilterSet):
class Meta:
model = Transaction
fields = {
'memo': [...],
}
However, when I run this, I get the following error:
Traceback (most recent call last):
...
class TransactionFilter(FilterSet):
File "/home/aaron/.virtualenvs/api/lib/python3.6/site-packages/graphene/utils/subclass_with_meta.py", line 52, in __init_subclass__
super_class.__init_subclass_with_meta__(**options)
File "/home/aaron/.virtualenvs/api/lib/python3.6/site-packages/graphene_sqlalchemy_filter/filters.py", line 262, in __init_subclass_with_meta__
filters_fields = cls._generate_default_filters(model, fields)
File "/home/aaron/.virtualenvs/api/lib/python3.6/site-packages/graphene_sqlalchemy_filter/filters.py", line 515, in _generate_default_filters
expressions, field_name, field_type, field_object['nullable']
File "/home/aaron/.virtualenvs/api/lib/python3.6/site-packages/graphene_sqlalchemy_filter/filters.py", line 563, in _generate_filter_fields
filter_field = field_type(description=doc)
TypeError: 'String' object is not callable
The error is coming from _generate_default_filters
from the following line:
field_type = convert_sqlalchemy_type(
column_type, field_object['column']
)
The field_type
that is returned is an instance of graphene.String()
, which is itself not callable. I'm still familiarizing myself with the code, but I think this should be getting the class String
and not an instance. My workaround (that seems to work) is to tack __class__
on the end of that call:
field_type = convert_sqlalchemy_type(
column_type, field_object['column']
).__class__
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.