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

如何在Django中创建含关联关系的GraphQL Mutation

创建关联酒店客人与房间的GraphQL Mutation方案

一、先修正ReservationNode的关联字段(重要)

你的ReservationNode中使用relay.ConnectionField定义关联字段是错误的——因为Reservations与Rooms、HotelGuests是多对一关联(一个预订对应一个客人/房间),应该用单个字段而非Connection(Connection用于一对多/多对多场景)。修正后的代码如下:

class ReservationNode(DjangoObjectType):
    in_room = graphene.Field(RoomNode, description='关联的房间')
    booked_by = graphene.Field(HotelGuestNode, description='预订的客人')

    def resolve_in_room(self, info):
        return self.room

    def resolve_booked_by(self, info):
        return self.hotel_guest

    class Meta:
        model = Reservations
        filter_fields = ['id',
                         'price',
                         'prepayment_price',
                         'number_of_guests',
                         'date_from',
                         'date_to',
                         'description',
                         'booking_status']
        interfaces = (relay.Node,)

二、创建Relay风格的Mutation(适配现有Node类)

1. 定义输入参数类型

import graphene
from graphene import relay
from .models import HotelGuests, Rooms, Reservations
from .types import ReservationNode

class CreateReservationInput(relay.InputObjectType):
    # 预订基础字段
    price = graphene.Float(required=True)
    prepayment_price = graphene.Float()
    number_of_guests = graphene.Int(required=True)
    date_from = graphene.Date(required=True)
    date_to = graphene.Date(required=True)
    description = graphene.String()
    booking_status = graphene.Int()
    # 关联对象ID(UUID类型,匹配模型主键)
    hotel_guest_id = graphene.UUID(required=True)
    room_id = graphene.UUID()  # 房间可选,匹配模型中room字段允许为空的设置

2. 定义Mutation处理类

class CreateReservation(relay.ClientIDMutation):
    # 返回创建后的预订对象
    reservation = graphene.Field(ReservationNode)

    class Input(CreateReservationInput):
        pass

    @classmethod
    def mutate_and_get_payload(cls, root, info, **input):
        # 1. 验证并获取关联的酒店客人
        try:
            hotel_guest = HotelGuests.objects.get(id=input['hotel_guest_id'])
        except HotelGuests.DoesNotExist:
            raise Exception("指定的酒店客人不存在")
        
        # 2. 可选:验证并获取关联的房间
        room = None
        if input.get('room_id'):
            try:
                room = Rooms.objects.get(id=input['room_id'])
            except Rooms.DoesNotExist:
                raise Exception("指定的房间不存在")
        
        # 3. 验证日期合法性(可选)
        if input['date_from'] >= input['date_to']:
            raise Exception("退房日期必须晚于入住日期")
        
        # 4. 验证客人数量符合房间限制(可选)
        if room and not (room.min_vacancy <= input['number_of_guests'] <= room.max_vacancy):
            raise Exception(f"该房间允许的客人数量范围是{room.min_vacancy}-{room.max_vacancy}")
        
        # 5. 创建预订记录
        reservation = Reservations.objects.create(
            price=input['price'],
            prepayment_price=input.get('prepayment_price', 0),
            number_of_guests=input['number_of_guests'],
            date_from=input['date_from'],
            date_to=input['date_to'],
            description=input.get('description'),
            booking_status=input.get('booking_status', 0),
            hotel_guest=hotel_guest,
            room=room
        )
        
        return CreateReservation(reservation=reservation)

3. 注册到Schema

class Mutation(graphene.ObjectType):
    create_reservation = CreateReservation.Field()

# 假设你已有Query类,将Mutation与Query整合到Schema
schema = graphene.Schema(query=Query, mutation=Mutation)

三、创建普通Graphene Mutation(无需Relay场景)

如果不需要适配Relay规范,也可以用普通Mutation写法:

class CreateReservationMutation(graphene.Mutation):
    class Arguments:
        price = graphene.Float(required=True)
        prepayment_price = graphene.Float()
        number_of_guests = graphene.Int(required=True)
        date_from = graphene.Date(required=True)
        date_to = graphene.Date(required=True)
        description = graphene.String()
        booking_status = graphene.Int()
        hotel_guest_id = graphene.UUID(required=True)
        room_id = graphene.UUID()

    reservation = graphene.Field(ReservationType)

    def mutate(self, info, **kwargs):
        # 验证关联对象逻辑同Relay版本
        hotel_guest = HotelGuests.objects.get(id=kwargs['hotel_guest_id'])
        room = Rooms.objects.get(id=kwargs['room_id']) if kwargs.get('room_id') else None

        # 创建预订
        reservation = Reservations.objects.create(
            price=kwargs['price'],
            prepayment_price=kwargs.get('prepayment_price', 0),
            number_of_guests=kwargs['number_of_guests'],
            date_from=kwargs['date_from'],
            date_to=kwargs['date_to'],
            description=kwargs.get('description'),
            booking_status=kwargs.get('booking_status', 0),
            hotel_guest=hotel_guest,
            room=room
        )

        return CreateReservationMutation(reservation=reservation)

# 注册到Mutation类
class Mutation(graphene.ObjectType):
    create_reservation = CreateReservationMutation.Field()

四、Mutation请求示例

Relay风格请求

mutation {
  createReservation(
    input: {
      price: 150.0
      prepaymentPrice: 30.0
      numberOfGuests: 2
      dateFrom: "2024-06-01"
      dateTo: "2024-06-07"
      description: "带阳台的海景房"
      bookingStatus: 1
      hotelGuestId: "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv"
      roomId: "wxyz-1234-5678-90ab-cdefghijklmn"
      clientMutationId: "test123"
    }
  ) {
    reservation {
      id
      price
      bookedBy {
        id
        name
        lastname
      }
      inRoom {
        id
        roomNumber
      }
    }
  }
}

普通风格请求

mutation {
  createReservation(
    price: 150.0
    prepaymentPrice: 30.0
    numberOfGuests: 2
    dateFrom: "2024-06-01"
    dateTo: "2024-06-07"
    description: "带阳台的海景房"
    bookingStatus: 1
    hotelGuestId: "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv"
    roomId: "wxyz-1234-5678-90ab-cdefghijklmn"
  ) {
    reservation {
      id
      price
      hotelGuest {
        id
        name
        lastname
      }
      room {
        id
        roomNumber
      }
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:02:02