Closed AndrewOwenMartin closed 5 years ago
You have models User, Address, UserAddress?
Filter may be like this
class AddressFilter(graphene_sqlalchemy_filter.FilterSet):
has_residents = graphene.InputField(lambda: UserFilter)
class Meta:
model = db.Address
fields = {"text": [...], "strong": [...]}
@classmethod
def has_residents_filter(cls, info, query, filters):
sub_query = db_session.query(db.User.id)
filtered_sub_query = UserFilter.filter(info, sub_query, filters)
# first arg is a query (graphene-sqlalchemy-filter>=1.7.0)
residents = cls.aliased(query, db.UserAddress, name='has_residents')
query = query.join(
residents,
and_(
db.Address.id == residents.address_id,
residents.user_id.in_(filtered_sub_query),
),
)
return query, residents.id.isnot(None)
UserFilter can be written by analogy.
Thank you, this will be helpful when I need to filter two ways through a join table. E.g. User, Address, UserAddress.
In my case, however, I just had Address and User with a simple one to many relation. One User can have many (email) Addresses, and each (email) Address belongs to exactly one user.
Your response is helpful to my case as it helps me see that I don't need to do filtering in both ways. I.e Filtering (email) Addresses by attributes of the User makes sense, but filtering Users by an attribute on their list of (email) Addresses doesn't make sense. If I do need to filter Users by attributes of their list of (email) Addresses then I can implement a filter function as you have described.
If you need to get one user by email. I think in your case more GraphQL way to write another field, like this
{
userByEmail(email: "admin@example.com") {id username}
}
or If you have a list of emails:
class UserFilter(FilterSet):
email_in = graphene.List(graphene.String)
@classmethod
def email_in_filter(cls, info, query, emails):
query = query.join(Address)
return query, Address.email.in_(emails)
allUsers(filters: {emailIn: ["a@example.com", "b@example.com"]}) {
edges { node { id username } }
}
If you want to get all addresses by user id:
class AddressFilter(FilterSet):
class Meta:
model = db.Address
fields = {"user_id": ['eq']}
{
allAddresses(filters: {userId: 1}) {
edges { node { id email } }
}
}
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 classAddressFilter
hasn't been defined.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.