代码之家  ›  专栏  ›  技术社区  ›  codemyown

如何在主对象序列化器中传递相关对象参数

  •  1
  • codemyown  · 技术社区  · 11 月前

    我有一个Room对象,它将具有一些设置。我想让房间和房间设置成为不同的对象,但彼此绑定。每当创建房间时,都会创建房间设置,所以我使用的是信号。但是,在创建房间时,我需要通过信号将RoomSetting参数从room传递到RoomSettings,这样我就可以在创建时设置设置。

    models.py

    from django.db import models
    from users.models import AppUser as UserModel
    from django.core.validators import MaxValueValidator, MinValueValidator
    
    import random, string
    from datetime import datetime
    
    def generate_unique_key():
        length = 10
        while True:
            key = ''.join(random.choices(string.ascii_uppercase, k=length))
            if Room.objects.filter(key=key).count() == 0:
                break
        return key
    
    class Room(models.Model):
        host = models.ForeignKey(UserModel, on_delete=models.CASCADE, related_name='rooms')
        key = models.CharField(max_length=10, default=generate_unique_key, unique=True, editable=False)
        created_at = models.DateTimeField(auto_now_add=True, editable=False)
        
        def __str__(self):
            return f'{self.key} - {self.host.username}'
        
        def get_chat(self):
            return self.chat
    
    class RoomSettings(models.Model):
        room = models.OneToOneField(Room, on_delete=models.CASCADE, related_name='settings')
        max_users = models.PositiveIntegerField(default=8, validators=[MaxValueValidator(8), MinValueValidator(1)])
        is_public = models.BooleanField(default=True)
        users_can_send_message = models.BooleanField(default=True)
    

    序列化程序.py

    from rest_framework import serializers
    
    from .models import Room, RoomSettings
    from users.serializers import UserSerializer
    from chats.serializers import RoomChatSerializer
    
    
    class SettingSerializer(serializers.ModelSerializer):
        class Meta:
            model = RoomSettings
            exclude = ['room']
    
            
    class CreateRoomSerializer(serializers.ModelSerializer):
        max_users = serializers.IntegerField()
        is_public = serializers.BooleanField()
        users_can_send_message = serializers.BooleanField()
        class Meta:
            model = Room
            fields = ['max_users', 'is_public', 'users_can_send_message']
    

    信号.py

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    from .models import Room, RoomSettings
    from chats.models import Chat
    
    @receiver(post_save, sender=Room)
    def post_save_create_room(sender, instance, created, **kwargs):
        if created:
            RoomSettings.objects.create(room=instance, **kwargs)
            Chat.objects.create(room=instance)
    

    views.py

    class CreateRoomView(CreateAPIView):
        permission_classes = [IsAuthenticated]
        serializer_class = CreateRoomSerializer
        
        def post(self, request, *args, **kwargs):
            serializer = self.serializer_class(data=request.data)
            if serializer.is_valid():
                room = Room.objects.create(host=self.request.user, **serializer.data)
                return JsonResponse(RoomSerializer(room).data, status=status.HTTP_201_CREATED)
    

    我试图将参数传递给CreateRoomView的端点,但遇到了错误。它应该使用给定的数据创建房间和房间设置。

    1 回复  |  直到 11 月前
        1
  •  1
  •   willeM_ Van Onsem    11 月前

    我真的不明白你为什么需要 RoomSettings 首先是模型,尤其是因为你每次都会创建一个 房间设置 记录a Room .a的目的 OneToOneField 是制作额外的模型(在这里 房间设置 )可选,但在这里,你似乎在“玩弄”两个模型,而没有用例将它们一分为二。

    只要把这些放在一起 型号:

    from django.conf import settings
    
    def generate_unique_key():
        length = 10
        while True:
            key = ''.join(random.choices(string.ascii_uppercase, k=length))
            if not Room.objects.filter(key=key).exists():
                break
        return key
    
    
    class Room(models.Model):
        host = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
            related_name='rooms',
            editable=False,
        )
        key = models.CharField(
            max_length=10, default=generate_unique_key, unique=True, editable=False
        )
        created_at = models.DateTimeField(auto_now_add=True)
        max_users = models.PositiveIntegerField(
            default=8, validators=[MaxValueValidator(8), MinValueValidator(1)]
        )
        is_public = models.BooleanField(default=True)
        users_can_send_message = models.BooleanField(default=True)
    
        def __str__(self):
            return f'{self.key} - {self.host.username}'
    
        def get_chat(self):
            return self.chat

    这将序列化器简化为:

    class RoomSerializer(serializers.ModelSerializer):
        max_users = serializers.IntegerField()
        is_public = serializers.BooleanField()
        users_can_send_message = serializers.BooleanField()
    
        class Meta:
            model = Room
            fields = ['max_users', 'is_public', 'users_can_send_message']

    从而创建对象以:

    class CreateRoomView(CreateAPIView):
        permission_classes = [IsAuthenticated]
        serializer_class = RoomSerializer
    
        def perform_create(self, serializer):
            serializer.save(host=request.user)

    注: :通常最好使用 settings.AUTH_USER_MODEL  [Django-doc] 参考用户模型,而不是使用 User model [Django-doc] 直接。有关更多信息,请参阅 referencing the User model section of the documentation [Django-doc] .


    注: :最好一起工作 .exists() Â [Django-doc] 检查记录是否存在,然后使用 .count() Â [Django-doc] 因为在找到记录后,计数可能不得不继续寻找记录。