如何在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
相关产品推荐
相关产品推荐

