How to best work with custom graphene.ObjectType
s with the optimizer?
#63
-
In my project, I've been using a customised version of the Before diving into specifics, at a high level, this is how it works: Here's what it looks like in code: First, the "taggable" code: from taggit.models import GenericUUIDTaggedItemBase, TagBase
from taggit.managers import TaggableManager
class Tag(TagBase):
class Meta:
unique_together = ("name", "category")
category = models.CharField(
db_index=True, default="custom", max_length=200, null=False
)
name = models.CharField(db_index=True, max_length=255)
class TaggedItem(GenericUUIDTaggedItemBase):
class Meta:
unique_together = [["content_type", "object_id", "tag"]]
confidence = models.FloatField()
class Taggable(models.Model):
class Meta:
abstract = True
tags = TaggableManager(blank=True, through=TaggedItem)
tagged_through = TaggedItem Then, any model that needs to be tagged can inherit the class CustomModel(Taggable):
.... On the GQL side, I represent this as custom object type, which is defined as follows: import graphene
class OzuTag(graphene.ObjectType):
category = graphene.String()
library_id = graphene.String()
name = graphene.String()
user_id = graphene.String()
class OzuTaggedItem(OzuTag):
confidence = graphene.Float()
tag_type = graphene.String()
class CustomObjectNode((DjangoObjectType):
tags = graphene.List(OzuTaggedItem)
# The original code has more robustness checks and if-else clauses, but I've reproduced
# a minimal version here for ease of demonstration
def resolve_tags(self, info):
res = []
for tagged_item in self.prefetched_tagged_items:
res.append(
{
"name": tagged_item.tag.name,
"category": tagged_item.tag.category,
"user_id": tagged_item.tag.user_id,
"library_id": tagged_item.tag.library_id,
"confidence": tagged_item.confidence,
"tag_type": tagged_item.tag_type,
}
)
class Query:
all_objects = DjangoFilterConnectionField(CustomObjectNode)
def resolve_all_objects(self, info):
qset = CustomObject.objects.all()
is_querying_for_tags, _ = check_for_field(info, "tags") # Checks incoming GQL query to see if 'tags' is queried for
if is_querying_for_tags:
tagged_items_prefetch = Prefetch(
"tagged_items",
queryset=(
TaggedItem.objects.filter(
object_id__in=qset.values_list("pk")
).select_related("tag")
),
to_attr="prefetched_tagged_items",
)
qset = qset.prefetch_related(tagged_items_prefetch)
return qset The above code is inefficient in that it doesn't do Also want to mention that if this isn't supported but can be, I'd be happy to put in a PR with some guidance. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
The issue here is that I might consider adding an option to hook into the optimization process with settings, but currently #61 and #62 take precedence. After those are resolved (I'm working on them), I'm willing to accept solutions for this. |
Beta Was this translation helpful? Give feedback.
-
Closing this discussion as there's now an ongoing PR for this: #67 |
Beta Was this translation helpful? Give feedback.
-
For closure, this has been solved in v0.5.1. Since I also mentioned adding hooks for configuring parts of the optimizer in this discussion, I'm announcing here that this is now possible in v0.6.0. Users can now simply subclass |
Beta Was this translation helpful? Give feedback.
For closure, this has been solved in v0.5.1.
Since I also mentioned adding hooks for configuring parts of the optimizer in this discussion, I'm announcing here that this is now possible in v0.6.0. Users can now simply subclass
OptimizationCompiler
,QueryOptimizer
,FilterInfoCompiler
, orFieldSelectionCompiler
, and the library will then use those subclasses internally. This allows modifying specific parts of them without rewriting large parts of the library that use those classes.