使用嵌套结构的参数使用 django-graphene 过滤父级
Using arguments to nested structures for filtering parents using django-graphene
我目前正在使用 Python & Django 和 Graphene 来为我的 Graphql 后端建模。我的问题类似于 Graphene 的回购 https://github.com/graphql-python/graphene/issues/431 上的这个问题。我也在使用 graphene_django_optimizer 库来提高性能。
但是我很难理解如何在我当前的情况下应用@syrusakbary 提出的解决方案来解决我的问题。任何帮助将不胜感激
这是我要执行的查询
getUser(userId: $userId)
{
id
username
trainings{
id
name
sessions{
id
createdAt
completedAt
category
}
}
}
}
训练正确,只有属于该特定用户 ID 的训练。但是,每次培训的所有课程都是为所有用户提供的。我希望会话也特定于该单个用户。在我的 types.py 上是相关类型
class SessionType(DjangoObjectType):
class Meta:
model = Session
fields = "__all__"
convert_choices_to_enum = False
@classmethod
def get_queryset(cls, queryset, info, **kwargs):
if info.context.user.is_anonymous:
return queryset.order_by('-id')
return queryset
class TrainingType(gql_optimizer.OptimizedDjangoObjectType):
class Meta:
model = Training
fields = "__all__"
convert_choices_to_enum = False
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
fields = "__all__"
以下是我的相关模型:
class Training(models.Model):
name = models.CharField(max_length=200, help_text='Training\'s name')
details = models.TextField(default="", help_text='Descriptive details about the training')
course = models.ForeignKey("Course", related_name="trainings", on_delete=models.CASCADE)
user = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="trainings")
metric_cards = models.TextField(default="", help_text="An object describing the metrics to be used. (Optional)")
def __str__(self):
return str(self.id) + ' - ' + self.name
class Session(models.Model):
name = models.CharField(max_length=200, help_text='Session\'s name')
category = models.CharField(max_length=240, choices=SESSION_CATEGORIES, default="practice",
help_text='Session type. Can be of \'assessment\''
'or \'practice\'')
total_steps = models.IntegerField(default=1, help_text='Amount of steps for this session')
created_at = models.DateTimeField(editable=False, default=timezone.now, help_text='Time the session was created'
'(Optional - default=now)')
completed_at = models.DateTimeField(editable=False, null=True, blank=True, help_text='Time the session was finished'
'(Optional - default=null)')
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="training_sessions", on_delete=models.DO_NOTHING)
training = models.ForeignKey("Training", related_name="sessions", on_delete=models.CASCADE)
def __str__(self):
return self.name
我的解析器在不同的文件中,根据每种类型,例如
class SessionQuery(graphene.ObjectType) 包含与会话相关的所有解析器。像这样:
class SessionQuery(graphene.ObjectType):
debug = graphene.Field(DjangoDebug, name='_debug')
# Session Queries
session = graphene.Field(SessionType, id=graphene.Int(), user_id=graphene.Int(required=True))
last_created_session = graphene.Field(SessionType)
all_sessions = graphene.List(SessionType,
first=graphene.Int(),
skip=graphene.Int(),)
latest_activities = graphene.List(LatestActivity, limit=graphene.Int())
activity_in_range = graphene.List(UserRangeActivity, start_date=graphene.Date(), end_date=graphene.Date())
unique_users_activity_in_range = graphene.Int(start_date=graphene.Date(), end_date=graphene.Date())
def resolve_last_created_session(root, info):
return Session.objects.latest('id')
def resolve_all_sessions(root, info,first=None,skip=None):
if skip:
return gql_optimizer.query(Session.objects.all().order_by('-id')[skip:], info)
elif first:
return gql_optimizer.query(Session.objects.all().order_by('-id')[:first], info)
else:
return gql_optimizer.query(Session.objects.all().order_by('-id'), info)
(只是部分代码,因为太多了,其余的无关紧要)
现在,据我所知,要实现我想要的,我需要在 TrainingQuery class 下有一个类似 resolve_sessions 的东西,我可以在其中有一个参数 user_id 我只是从嵌套链中传递下来。但是我没有那个领域的解析器。 Sessions是Session的一个列表,在Training模型中是一个外键,当我在查询中有这样的东西时,会自动带上这个列表:
training
{
id
name
sessions {
id
name
}
}
我想我想要实现的查询应该是这样的:
query getUser($userId: Int!) {
getUser(userId: $userId)
{
id
username
trainings{
id
name
sessions(userId: Int){
id
createdAt
completedAt
category
}
}
}
}
但是place/resolver我可以在哪个地方实现这样的事情呢?它是在我的 SessionType 上的 get_queryset 方法中吗?如果是,怎么做?
我走的路对吗?
听起来您想修改 TrainingType
上的 sessions
字段以添加新参数,并向 class 添加 resolve_sessions
方法。
根据我在你的问题中看到的内容,应该是这样的:
class TrainingType(graphene.ObjectType):
# other fields omitted
sessions = graphene.List(
SessionType,
user_id=graphene.ID(),
first=graphene.Int(),
skip=graphene.Int(),
)
def resolve_sessions(self, info, user_id=None, first=None, skip=None):
# Change this to do something other than return an empty list
return []
我找到了解决方案。是的,我走在正确的轨道上。问题实际上是关于石墨烯的糟糕文档。我必须打开 ResolveInfo 对象的源代码。可以看到here
基本上,在查询的父级传递的参数在info.variable_values下可用。所以我需要做的就是修改 get_queryset 方法并像这样做:
class SessionType(DjangoObjectType):
class Meta:
model = Session
fields = "__all__"
convert_choices_to_enum = False
@classmethod
def get_queryset(cls, queryset, info, **kwargs):
if info.variable_values.get('userId') and info.variable_values.get('userId') is not None:
return queryset.filter(Q(user_id=info.variable_values.get('userId')))
return queryset
这是一件很重要的事情,我们通常希望过滤器以这种方式工作。我希望他们将这个“技巧”添加到他们的文档中。希望这个答案能帮助遇到同样问题的其他人
我目前正在使用 Python & Django 和 Graphene 来为我的 Graphql 后端建模。我的问题类似于 Graphene 的回购 https://github.com/graphql-python/graphene/issues/431 上的这个问题。我也在使用 graphene_django_optimizer 库来提高性能。
但是我很难理解如何在我当前的情况下应用@syrusakbary 提出的解决方案来解决我的问题。任何帮助将不胜感激
这是我要执行的查询
getUser(userId: $userId)
{
id
username
trainings{
id
name
sessions{
id
createdAt
completedAt
category
}
}
}
}
训练正确,只有属于该特定用户 ID 的训练。但是,每次培训的所有课程都是为所有用户提供的。我希望会话也特定于该单个用户。在我的 types.py 上是相关类型
class SessionType(DjangoObjectType):
class Meta:
model = Session
fields = "__all__"
convert_choices_to_enum = False
@classmethod
def get_queryset(cls, queryset, info, **kwargs):
if info.context.user.is_anonymous:
return queryset.order_by('-id')
return queryset
class TrainingType(gql_optimizer.OptimizedDjangoObjectType):
class Meta:
model = Training
fields = "__all__"
convert_choices_to_enum = False
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
fields = "__all__"
以下是我的相关模型:
class Training(models.Model):
name = models.CharField(max_length=200, help_text='Training\'s name')
details = models.TextField(default="", help_text='Descriptive details about the training')
course = models.ForeignKey("Course", related_name="trainings", on_delete=models.CASCADE)
user = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="trainings")
metric_cards = models.TextField(default="", help_text="An object describing the metrics to be used. (Optional)")
def __str__(self):
return str(self.id) + ' - ' + self.name
class Session(models.Model):
name = models.CharField(max_length=200, help_text='Session\'s name')
category = models.CharField(max_length=240, choices=SESSION_CATEGORIES, default="practice",
help_text='Session type. Can be of \'assessment\''
'or \'practice\'')
total_steps = models.IntegerField(default=1, help_text='Amount of steps for this session')
created_at = models.DateTimeField(editable=False, default=timezone.now, help_text='Time the session was created'
'(Optional - default=now)')
completed_at = models.DateTimeField(editable=False, null=True, blank=True, help_text='Time the session was finished'
'(Optional - default=null)')
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="training_sessions", on_delete=models.DO_NOTHING)
training = models.ForeignKey("Training", related_name="sessions", on_delete=models.CASCADE)
def __str__(self):
return self.name
我的解析器在不同的文件中,根据每种类型,例如 class SessionQuery(graphene.ObjectType) 包含与会话相关的所有解析器。像这样:
class SessionQuery(graphene.ObjectType):
debug = graphene.Field(DjangoDebug, name='_debug')
# Session Queries
session = graphene.Field(SessionType, id=graphene.Int(), user_id=graphene.Int(required=True))
last_created_session = graphene.Field(SessionType)
all_sessions = graphene.List(SessionType,
first=graphene.Int(),
skip=graphene.Int(),)
latest_activities = graphene.List(LatestActivity, limit=graphene.Int())
activity_in_range = graphene.List(UserRangeActivity, start_date=graphene.Date(), end_date=graphene.Date())
unique_users_activity_in_range = graphene.Int(start_date=graphene.Date(), end_date=graphene.Date())
def resolve_last_created_session(root, info):
return Session.objects.latest('id')
def resolve_all_sessions(root, info,first=None,skip=None):
if skip:
return gql_optimizer.query(Session.objects.all().order_by('-id')[skip:], info)
elif first:
return gql_optimizer.query(Session.objects.all().order_by('-id')[:first], info)
else:
return gql_optimizer.query(Session.objects.all().order_by('-id'), info)
(只是部分代码,因为太多了,其余的无关紧要)
现在,据我所知,要实现我想要的,我需要在 TrainingQuery class 下有一个类似 resolve_sessions 的东西,我可以在其中有一个参数 user_id 我只是从嵌套链中传递下来。但是我没有那个领域的解析器。 Sessions是Session的一个列表,在Training模型中是一个外键,当我在查询中有这样的东西时,会自动带上这个列表:
training
{
id
name
sessions {
id
name
}
}
我想我想要实现的查询应该是这样的:
query getUser($userId: Int!) {
getUser(userId: $userId)
{
id
username
trainings{
id
name
sessions(userId: Int){
id
createdAt
completedAt
category
}
}
}
}
但是place/resolver我可以在哪个地方实现这样的事情呢?它是在我的 SessionType 上的 get_queryset 方法中吗?如果是,怎么做?
我走的路对吗?
听起来您想修改 TrainingType
上的 sessions
字段以添加新参数,并向 class 添加 resolve_sessions
方法。
根据我在你的问题中看到的内容,应该是这样的:
class TrainingType(graphene.ObjectType):
# other fields omitted
sessions = graphene.List(
SessionType,
user_id=graphene.ID(),
first=graphene.Int(),
skip=graphene.Int(),
)
def resolve_sessions(self, info, user_id=None, first=None, skip=None):
# Change this to do something other than return an empty list
return []
我找到了解决方案。是的,我走在正确的轨道上。问题实际上是关于石墨烯的糟糕文档。我必须打开 ResolveInfo 对象的源代码。可以看到here
基本上,在查询的父级传递的参数在info.variable_values下可用。所以我需要做的就是修改 get_queryset 方法并像这样做:
class SessionType(DjangoObjectType):
class Meta:
model = Session
fields = "__all__"
convert_choices_to_enum = False
@classmethod
def get_queryset(cls, queryset, info, **kwargs):
if info.variable_values.get('userId') and info.variable_values.get('userId') is not None:
return queryset.filter(Q(user_id=info.variable_values.get('userId')))
return queryset
这是一件很重要的事情,我们通常希望过滤器以这种方式工作。我希望他们将这个“技巧”添加到他们的文档中。希望这个答案能帮助遇到同样问题的其他人