You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Graphene-Django中Update与Delete Mutation返回Null问题求助

Django + graphene-django 中Update/Delete Mutation返回success为null的问题

我在Django应用里用graphene-django集成GraphQL Schema,已实现全量查询、单条查询,以及创建、更新、删除Mutation。但Update和Delete端点无法正常工作,执行后返回的success字段为null。


1. Model代码

COUNTRIES = (
    ("sierra leone",  "Sierra Leone"),
    ("guinea", "Guinea"),
)

class School(models.Model):
    name = models.CharField(_("Name"), max_length=255)
    abreviation = models.CharField(_("Abreviation"), max_length=10)
    label = models.TextField(_("Label"), max_length=255, blank=True, null=True)
    school_id = models.CharField(_("School ID"), max_length=100, unique=True, blank=True, null=True)
    adresse_line_1 = models.CharField(_("Adresse Line 1"), max_length=255, blank=True)
    adresse_line_2 = models.CharField(_("Adresse Line 2"), max_length=255, blank=True)
    city = models.CharField(_("City"), max_length=255, blank=True)
    country = models.CharField(max_length=60, choices=COUNTRIES, blank=True, null=True)
    phone_number = models.CharField(_("Phone number"), max_length=15)
    email = models.EmailField(_("Email"))
    website = models.CharField(_("Website"), max_length=50, blank=True)
    logo = models.ImageField(_("Logo"), upload_to='logo/', blank=True)
    small_logo = models.ImageField(_("Small Logo"), upload_to='logo/', blank=True, null=True)
    site_favicon = models.ImageField(_("Favicon"), upload_to='logo/', blank=True, null=True)

2. Update和Delete Mutation代码

class SchoolType(DjangoObjectType):
    class Meta:
        model = School
        fields = (
            "name",
            "abreviation",
            "label",
            "school_id",
            "adresse_line_1",
            "adresse_line_2",
            "city",
            "country",
            "phone_number",
            "email",
            "website",
            "logo",
            "small_logo",
            "site_favicon",
        )
        interfaces = (graphene.relay.Node,)
        convert_choices_to_enum = False

class UpdateSchoolMutation(graphene.Mutation):
    school = graphene.Field(SchoolType)
    success = graphene.Boolean()

    class Arguments:
        id = graphene.String(required=True)
        name = graphene.String()
        abreviation = graphene.String()
        label = graphene.String()
        school_id = graphene.String()
        adresse_line_1 = graphene.String()
        adresse_line_2 = graphene.String()
        city = graphene.String()
        country = graphene.String()
        phone_number = graphene.String()
        email = graphene.String()
        website = graphene.String()
        logo = Upload()
        small_logo = Upload()
        site_favicon = Upload()

    @classmethod
    def mutate(self, info, id, **kwargs):
        id = int(from_global_id(id)[1])

        try:
            school = School.objects.get(pk=id)
        except School.DoesNotExist:
            raise Exception("School does not exist".format(id))

        for field, value in kwargs.items():
            setattr(school, field, value)

        school.save()
        return UpdateSchoolMutation(school=school, success=True)


class DeleteSchoolMutation(graphene.Mutation):
    success = graphene.Boolean()

    class Arguments:
        id = graphene.String(required=True)

    @classmethod
    def mutate(self, info, id, **kwargs):
        id = int(from_global_id(id)[1])
        
        try:
            school = School.objects.get(pk=id)
        except School.DoesNotExist:
            raise Exception("School does not exist".format(id))

        school.archived = True
        school.save()
        return DeleteSchoolMutation(success=True)

3. 测试Delete Mutation及结果

执行的Mutation:

mutation {
  deleteSchool(id: "U2Nob29sVHlwZToy") {
    success
  }
}

返回结果:

{
  "data": {
    "deleteSchool": {
      "success": null
    }
  }
}

Update Mutation出现完全相同的问题。

4. 依赖版本

django==4.0.8
graphene-django==3.0.0
django-filter==22.1
django-graphql-jwt==0.3.4
graphene-file-upload==1.3.0

问题原因及修复方案

核心问题1:类方法参数错误

graphene-django 3.x版本中,Mutation的mutate类方法第一个参数必须是cls(指代类本身),而非self(实例对象)。当前代码用self会导致方法上下文混乱,返回的对象无法正确映射到定义的字段。

核心问题2:Delete逻辑操作不存在字段

School模型中没有archived字段,但DeleteMutation里执行了school.archived = True,这会触发AttributeError。由于GraphQL的错误处理机制可能掩盖异常,最终导致success返回null。

修复步骤

  1. 修正mutate方法参数
    将两个Mutation的mutate方法第一个参数从self改为cls:

    # UpdateSchoolMutation的mutate方法
    @classmethod
    def mutate(cls, info, id, **kwargs):
        # 原有逻辑不变
    
    # DeleteSchoolMutation的mutate方法
    @classmethod
    def mutate(cls, info, id, **kwargs):
        # 原有逻辑不变
    
  2. 修复Delete逻辑

    • 若要物理删除数据:将school.archived = True改为school.delete();
    • 若要软删除:先在School模型中添加字段并迁移数据库:
      # 在School模型中新增字段
      archived = models.BooleanField(default=False)
      
      再执行school.archived = True的逻辑。
  3. (可选)优化异常提示
    将通用Exception替换为graphene的ValidationError,返回更清晰的错误信息:

    from graphene import ValidationError
    
    # ...
    except School.DoesNotExist:
        raise ValidationError(f"School with ID {id} does not exist")
    

内容的提问来源于stack exchange,提问作者Harith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:50:10