在没有中继的情况下使用带有graphene-django的子字段中的参数进行分页

Posted

技术标签:

【中文标题】在没有中继的情况下使用带有graphene-django的子字段中的参数进行分页【英文标题】:Use parameters in subfields with graphene-django without relay for pagination purpose 【发布时间】:2022-01-08 00:42:33 【问题描述】:

我正在将石墨烯与 django 一起使用,我正在努力做一些我认为应该非常简单的事情,但我没有发现它在石墨烯文档或 github 的任何地方都有记录,我也没有在这里看到类似的问题。我发现最接近它的是: https://www.howtographql.com/graphql-python/8-pagination/ 但如您所见,我必须在父解析器中声明我不想声明的参数。

我有这样的查询

  getUser(id: $userIdTarget) 
    id
    username
    trainings
      id
      name
      sessions
        id
        name
      
    
  

我想在会话子字段中实现分页。所以这就是我想要的:

  getUser(id: $userIdTarget) 
    id
    username
    trainings
      id
      name
      sessions(first:10)
        id
        name
      
    
  

在解析器中我会实现这样的东西:

def resolve_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)

(gql_optimizer 只是我使用的一个优化包装库)

但是这不起作用,因为字段会话对应于模型 Session 的列表,该列表是根据我的 django 模型进行训练的 fk,因此石墨烯会自动解决此问题,因为这些类型是 DjangoObjectType ,所以我不确定如何自定义这些解析器(或者是否可能)。

我将在下面留下相关的模型和类型:

会话模型

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)')
    is_complete = models.BooleanField(default=0)
    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 UserType(DjangoObjectType):
    class Meta:
        model = get_user_model()
        fields = "__all__"


    @classmethod
    def get_queryset(cls, queryset, info, **kwargs):
        if info.variable_values.get('orgId') and info.variable_values.get('orgId') is not None:
            return queryset.order_by('username')
        return 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'))).order_by('-id')
        return queryset

培训类型

class TrainingType(gql_optimizer.OptimizedDjangoObjectType):
    class Meta:
        model = Training
        fields = "__all__"
        convert_choices_to_enum = False

【问题讨论】:

【参考方案1】:

可以扩展您的类型以添加​​更多不在 Django 模型中的字段——也许这就是您正在寻找的向查询中注入更多数据的技术?

class TrainingType(gql_optimizer.OptimizedDjangoObjectType):
    my_extra_field = graphene.Int() # for example

    class Meta:
        model = Training
        fields = "__all__"
        convert_choices_to_enum = False

您还可以覆盖使用DjangoObjectType 创建的默认解析器。

【讨论】:

我将其标记为正确答案,并在我阅读时表示赞成,这一切都是有道理的,似乎是答案。今天我有机会尝试,不幸的是它并没有解决问题。这不适用于从外键关系自动创建的子字段 您还可以将对象添加为附加字段,然后进一步扩展您的自定义解析以填充这些字段。

以上是关于在没有中继的情况下使用带有graphene-django的子字段中的参数进行分页的主要内容,如果未能解决你的问题,请参考以下文章

在没有查看器的情况下中继现代分页

使用带有json字符串列的中继器

Relay Modern - 如何在没有 fragmentContainer 的情况下使用 fetchQuery

如何在不推送到服务器的情况下更新中继存储

中继器中的 ACF 图像不起作用

将传入令牌中继到其他服务