Django Graphene含外键与多对多关系模型的Mutation失效问题
Django GraphQL 创建Post Mutation失效问题
Django应用中定义了Tag和Post两个模型,Tag的Mutation可正常工作,数据查询功能也运行正常,但执行创建Post的Mutation后返回post: null,操作失效。
代码片段
models.py
from django.db import models from django.utils.translation import gettext as _ from django.conf import settings from django.contrib.auth import get_user_model User = get_user_model() # Create your models here. class Tag(models.Model): name = models.CharField(_("Tag Name"), max_length=50, unique=True) def __str__(self): return self.name class Post(models.Model): title = models.CharField(_("Title"), max_length=50, unique=True) slug = models.SlugField(_("Post Slug"), unique=True) body = models.TextField(_("Post Content")) createdAt = models.DateTimeField(auto_now_add=True) updatedAt = models.DateTimeField(auto_now=True) published = models.BooleanField(_("Published"), default=False) author = models.ForeignKey(User, verbose_name=_("Author"), on_delete=models.CASCADE) tags = models.ManyToManyField("Tag", verbose_name=_("Tags"), blank=True) class Meta: ordering = ['-createdAt'] def __str__(self): return self.title
schema.py
import graphene from graphene_django import DjangoObjectType from django.contrib.auth import get_user_model from .models import Post, Tag User = get_user_model() class PostType(DjangoObjectType): class Meta: model = Post class TagType(DjangoObjectType): class Meta: model = Tag fields = ('id', 'name',) class TagInput(graphene.InputObjectType): name = graphene.String(required=True) class CreatePostMutation(graphene.Mutation): class Arguments: title = graphene.String() body = graphene.String() published = graphene.Boolean() author_id = graphene.ID() tags = graphene.List(graphene.Int) success = graphene.Boolean() post = graphene.Field(PostType) @classmethod def mutate(cls, root, info, title, body, published, author_id, tags): author = User.objects.get(pk=author_id) post_instance = Post( title=title, body=body, published=published, author=author, ) post_instance.save(commit=False) if tags: tag_objects = Tag.objects.filter(pk__in=tags) post_instance.tags.set(tag_objects) post_instance.save() return CreatePostMutation(success=True, post=post_instance) class CreateTagMutation(graphene.Mutation): class Arguments: name = graphene.String(required=True) tag = graphene.Field(TagType) @classmethod def mutate(cls, root, info, name): tag = Tag(name=name) tag.save() return CreateTagMutation(tag=tag) class Mutation(graphene.ObjectType): create_post = CreatePostMutation.Field() create_tag = CreateTagMutation.Field() schema = graphene.Schema(query=Query, mutation=Mutation)
执行结果
{ "data": { "createPost": { "post": null } } }
问题原因及修复方案
核心问题
- 缺失必填字段
slug:Post模型中slug是SlugField(unique=True),属于必填字段,但CreatePostMutation的参数中未接收该值,创建Post实例时也未设置,导致Django模型校验失败,无法保存。 save(commit=False)使用错误:多对多关系(tags)需要在实例被保存到数据库(拥有主键ID)后才能关联,commit=False会阻止实例写入数据库,此时设置tags会失败。
修复代码
修改CreatePostMutation的参数和mutate方法:
from django.utils.text import slugify # 导入slug生成工具 class CreatePostMutation(graphene.Mutation): class Arguments: title = graphene.String(required=True) # 设为必填,匹配模型约束 body = graphene.String(required=True) published = graphene.Boolean(default=False) author_id = graphene.ID(required=True) tags = graphene.List(graphene.Int) slug = graphene.String() # 可选参数,若不传则自动生成 success = graphene.Boolean() post = graphene.Field(PostType) @classmethod def mutate(cls, root, info, title, body, author_id, published=False, tags=None, slug=None): author = User.objects.get(pk=author_id) # 自动生成slug(如果未传入) if not slug: slug = slugify(title) # 创建Post实例并直接保存到数据库 post_instance = Post( title=title, slug=slug, body=body, published=published, author=author, ) post_instance.save() # 实例已保存,关联tags if tags: tag_objects = Tag.objects.filter(pk__in=tags) post_instance.tags.set(tag_objects) return CreatePostMutation(success=True, post=post_instance)
额外优化建议
- 为模型字段的必填约束匹配GraphQL参数的
required=True,避免无效请求。 - 处理
User.DoesNotExist和Tag.DoesNotExist异常,返回明确的错误信息,比如:from django.core.exceptions import ObjectDoesNotExist try: author = User.objects.get(pk=author_id) except ObjectDoesNotExist: raise graphene.ValidationError("指定的作者不存在")
内容的提问来源于stack exchange,提问作者B14ck Dz
相关产品推荐
相关产品推荐

