I have a GraphQL query that will return purchase orders and the products that go with those purchase orders. I have set up two filters, the first being on the username that is associated with a purchase order, and another filter on the product name for products for the purchase orders.
If a user were to search for a particular product, I would like to only return orders that contain that product. At the moment, it still returns all purchase orders, but removes the product data that doesn't match the search criteria.
The database structure is a table that contains the purchase orders called purchase_orders
and a purchase order products tables called purchase_orders_products
that has a FK called order_id
to the purchase order id field.
For example, in the response below, if purchaseOrdersProductsOrderId.edges
is empty, I don't need to return the order data for ThisIsUsername
.
Schema
# region Integration Purchase Orders
class PurchasesProducts(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
class Meta:
model = purchase_orders_products
interfaces = (relay.Node,)
filter_fields = {'product_name': ['icontains']}
class Purchases(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
products = ArtsyConnectionField(PurchasesProducts)
class Meta:
model = purchase_orders
interfaces = (relay.Node,)
filter_fields = {'date': ['gt', 'lt', 'isnull'], 'username': ['icontains'],}
connection_class = ArtsyConnection
@staticmethod
def resolve_products(self, info, **kwargs):
return purchase_orders_products.objects.filter(order_id=self.id).order_by('product_name').all()
class PurchasesQuery(ObjectType):
purchases = ArtsyConnectionField(Purchases)
date_filter_list = graphene.List(graphene.List(graphene.String))
@staticmethod
def resolve_date_filter_list(self, info, **kwargs):
years = purchase_orders.objects.filter(user_id=info.context.user.id).annotate(year=ExtractYear('date'), month=ExtractMonth('date'),).order_by().values_list('year', 'month').order_by('-year', '-month').distinct()
return years
@staticmethod
def resolve_purchases(self, info, date_filter=None, **kwargs):
return purchase_orders.objects.filter(user_id=info.context.user.id).all().order_by("-date")
purchasesSchema = graphene.Schema(query=PurchasesQuery)
# endregion
Query
{
dateFilterList
purchases(first: 15, after: "") {
pageCursors {
...
}
edges {
node {
id
...
products(productName_Icontains: "access") {
edges {
node {
id
productId
productName
productNumber
}
}
}
}
}
}
}
Response
{
"data": {
"dateFilterList": [
...
],
"purchases": {
"pageCursors": {
...
},
"edges": [
{
"node": {
"id": "ab0d9542-480a-4a99-8f49-3474e820beb0",
"username": "ThisIsUsername",
...
"products": {
"edges": []
}
}
},
{
"node": {
"id": "03e937b2-5b67-4161-90de-cdeda8dcd065",
"username": "barry1234",
...
"products": {
"edges": [
{
"node": {
"id": "f9945e45-59ef-42e9-9b06-988f24d1c8ed",
"productId": "84fae6ca-8a16-45ee-b36f-31a0ba134866",
"productName": "Access Denied",
"productNumber": "47"
}
}
]
}
}
},
...
You should define filter for product_name
at Purchases
instead of PurchaseProducts
. The most straightforward way to do it is defining filterset_class
.
In my example, I have simplified a little bit queries and used DjangoFilterConnectionField
because I dont know what is ArtsyConnectionField
.
from django_filters import CharFilter, FilterSet
class PurchaseOrderFilter(FilterSet):
class Meta:
model = purchase_orders
fields = {'date': ['gt', 'lt', 'isnull'], 'username': ['icontains'],}
products__product_name = CharFilter(lookup_expr="icontains",)
class PurchaseOrderProductFilter(FilterSet):
class Meta:
model = purchase_orders_products
fields = {"name": ["icontains"]}
class PurchasesProducts(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
class Meta:
model = purchase_orders_products
interfaces = (graphene.relay.Node,)
filterset_class = PurchaseOrderProductFilter
class Purchases(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
products = DjangoFilterConnectionField(PurchasesOrderProduct)
class Meta:
model = purchases_orders
interfaces = (graphene.relay.Node,)
filterset_class = PurchaseOrderFilter
@staticmethod
def resolve_products(self, info, **kwargs):
return PurchaseOrderProduct.objects.filter(order_id=self.id).order_by('product_name').all()
Now your query would look like:
query {
purchases(first: 15, after: "", products_ProductName: "access") {
edges {
node {
products {
edges {
node {
productName
}
}
}
}
}
}
}
And the response:
{
"data": {
"purchases": {
"edges": [
{
"node": {"products": {"edges": [{"node": {"productName": "access1"}}]}}
}
]
}
}
}