如何在django中引用一个多对多字段,它接受不同的用户

rryofs0p  于 2023-04-22  发布在  Go
关注(0)|答案(1)|浏览(85)

我正在构建一个Django模型,用于创建各种用户的投票,他们可以互相邀请。
Models.py

class Participant(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)

class DateTimeRange(models.Model):
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()

class AvailabilityPoll(models.Model):
    name = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    duration = models.TimeField()
    datetime_ranges = models.ManyToManyField(DateTimeRange, related_name='datetime_ranges')
    deadline = models.DateTimeField()
    participants = models.ManyToManyField(Participant, related_name='participants')

    def is_expired(self):
        return self.deadline <= timezone.now()

    def get_participant_count(self):
        return self.participants.count()

我使用Django Rest Framework为POST API创建了一个视图和一个序列化器来创建这个视图:Views.py

class AvailabilityPollView(APIView):
    permission_classes = (IsAuthenticated, )
    serializer_class = AvailabilityPollSerializer

    @swagger_auto_schema(request_body=serializer_class, responses={201: serializer_class})
    def post(self, request):
        poll = request.data
        serializer = self.serializer_class(data=poll)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Serializers.py

from rest_framework import serializers
from django.contrib.auth import get_user_model
from polls.models import AvailabilityPoll, DateTimeRange

User = get_user_model()

class ParticipantsSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['email']

class DateTimeRangeSerializer(serializers.ModelSerializer):
    class Meta:
        model = DateTimeRange
        fields = '__all__'
    
    def create(self, validated_data):
        range = DateTimeRange.objects.create(start_time=validated_data['start_time'], end_time=validated_data['end_time'])
        range.save()
        return range

class AvailabilityPollSerializer(serializers.ModelSerializer):
    datetime_ranges = DateTimeRangeSerializer(many=True)
    participants = ParticipantsSerializer(many=True)

    class Meta:
        model = AvailabilityPoll
        fields = '__all__'

    def create(self, validated_data):
        datetime_ranges_data = validated_data.pop('datetime_ranges')
        participants_data = validated_data.pop('participants')
        poll = AvailabilityPoll.objects.create(**validated_data)

        for range in datetime_ranges_data:
            poll.datetime_ranges.add(DateTimeRangeSerializer.create(self, validated_data=range))

        for participant in participants_data:
            user = User.objects.get(email=participant['email'])
            poll.users.add(user)

        return poll

当我尝试在postman中使用我已经创建的用户作为参与者进行测试时,我得到一个错误,说具有此电子邮件的用户已经存在。我在这里做错了什么?我如何将多个现有用户引用到单个Poll模型?我正在使用一个自定义用户模型,该模型将电子邮件作为主要字段。
Json post body:

{
    "name":  "TestPoll",
    "description": "Test",
    "datetime_ranges" : [
        {
            "start_time": "2023-05-01T10:00:00Z",
            "end_time": "2023-05-01T12:00:00Z"
        },
        {
            "start_time": "2023-05-01T14:00:00Z",
            "end_time": "2023-05-01T16:00:00Z"
        }
    ],
    "participants": [
        {
            "email": "test@test.com"
        },
        {
            "email" : "test2@test2.com"
        }
    ],
    "duration": "1:00:00",
    "deadline": "2023-05-01T00:00:00Z"
}

我尝试创建这个参与者模型并使用外键来引用它。我期望创建一个将用户引用为其参与者的Polls对象。

zxlwwiss

zxlwwiss1#

很可能你想做的是使用**SlugRelatedField**[Django-doc]:

from rest_framework import serializers
from rest_framework.serializers import SlugRelatedField

class AvailabilityPollSerializer(serializers.ModelSerializer):
    datetime_ranges = DateTimeRangeSerializer(many=True)
    participants = SlugRelatedField(
        slug_field='email', queryset=User.objects.all(), many=True
    )

    class Meta:
        model = AvailabilityPoll
        fields = '__all__'

所以不需要执行.create逻辑。Django会自动查找并添加这些项。
数据也更加简洁:

{
    "name":  "TestPoll",
    "description": "Test",
    "datetime_ranges" : [
        {
            "start_time": "2023-05-01T10:00:00Z",
            "end_time": "2023-05-01T12:00:00Z"
        },
        {
            "start_time": "2023-05-01T14:00:00Z",
            "end_time": "2023-05-01T16:00:00Z"
        }
    ],
    "participants": ["test@test.com", "test2@test2.com"],
    "duration": "1:00:00",
    "deadline": "2023-05-01T00:00:00Z"
}

由于可用性轮询有一个持续时间,我不太清楚为什么范围有开始和结束日期。通过只指定开始时间戳,我们可以导出结束时间戳,只需将持续时间添加到它。

相关问题