Django:尝试使用保留创建会议室 API

Posted

技术标签:

【中文标题】Django:尝试使用保留创建会议室 API【英文标题】:Django: Trying to create a Meeting Room API with Reservations 【发布时间】:2021-03-02 09:32:01 【问题描述】:

所以我得到了这些任务:

创建会议室

获取会议室预订和按员工过滤的可能性

创建预订(预订有标题、起止日期、 员工)

首先我创建了一个会议室,这是模型:

class MeetingRooms(models.Model):
    public_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False, max_length=36)

    creator = models.ForeignKey(Employees, on_delete=models.CASCADE)
    reservations = models.ManyToManyField(MeetingRoomsReservations, blank=True)
    secret_key = models.CharField(max_length=128, null=False, blank=False)
    date_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "MeetingRooms"

    def __str__(self):
        return str(self.id)

所以任务说我需要创建某种预订,所以基本上我在想我可以创建reservations 对象并使其成为ManyToManyField,这样它就可以为不同的用户提供许多预订,想象一下会议可以有大概有 10 个人。

然后我创建了MeetingRoomsReservations 模型来处理所有预订:

class MeetingRoomsReservations(models.Model):
    statusTypes = [
        (0, "Valid"),
        (1, "Cancelled")
    ]

    receiver = models.ForeignKey(Employees, on_delete=models.CASCADE)
    meeting_room = models.ForeignKey('MeetingRooms', on_delete=models.CASCADE, default=None)
    title = models.CharField(max_length=150, blank=False, null=False)
    status = models.IntegerField(choices=statusTypes, null=False, blank=False, default=0)

    date_from = models.DateTimeField()
    date_to = models.DateTimeField()


    class Meta:
        db_table = "MeetingRoomsReservations"

    def __str__(self):
        return str(self.id)

据我了解的逻辑,MeetingRoomsReservations 将处理为 MeetingRoom 注册的所有预订。

MeetingRoom > Reservations > [ List Of Reservations ] = 每个预订都有时间等。

好的,现在我必须创建 API 端点:

from main.models import MeetingRooms, MeetingRoomsReservations
from rest_framework import viewsets, generics
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from .serializers import MeetingRoomSerializer, ReservationSerializer

from django.http import JsonResponse

class MeetingRoomViewSet(viewsets.ModelViewSet):

    permission_classes = [
        AllowAny
    ]

    queryset = MeetingRooms.objects.all()
    serializer_class = MeetingRoomSerializer

    def perform_create(self, serializer):
        serializer.save()


class ReservationViewSet(viewsets.ModelViewSet):

现在剩下的就是创建一个序列化器?听起来容易吗?让我们看看..

从 rest_framework 导入序列化程序 从 main.models 导入 MeetingRooms、MeetingRoomsReservations

class ReservationSerializer(serializers.ModelSerializer):
  class Meta:
    model = MeetingRoomsReservations
    fields = ('receiver', 'meeting_room', 'status', 'title', 'date_from', 'date_to')


class MeetingRoomSerializer(serializers.ModelSerializer):
  class Meta:
    model = MeetingRooms
    fields = ('creator', 'public_id', 'creator', 'date_created', 'secret_key', 'reservations')
    extra_kwargs = 'secret_key': 'write_only': True, 'min_length': 8

让我们看看我们的 Rest Framework:

所以现在是我不明白的部分。要创建会议室,仅发布这些值就足够了吗?

创建会议室后,应如何添加预订?

经过数小时的尝试,我无法正确创建预订并将其分配到特定的会议室。如何正确处理这个操作?

【问题讨论】:

不要在rooms api 中公开reservations,除非您希望它们是只读的。但是,我建议使用不同的端点 /rooms/<id>/reservations,您可以在其中获得具有该 ID 的会议室的所有预订,以及任何其他 CRUD 操作。 【参考方案1】:

让我帮助您克服设计模型的最初障碍,因为您似乎在某些模型中有一些不应该存在的字段。我们从 2 个实体开始:员工和会议室。员工将有一个基本的员工 ID、名字和姓氏。会议室将有一个用于内部索引的 ID,以及一个唯一的房间号。此房间号类似于您在公司办公室的会议室中看到的房间号。房间号可能包含字母字符,因此我们的字段将是 CharField

为了遵循您的一些设计惯例,我将在所有模型中使用 UUIDField 作为primary_key 字段。此外,为了简洁起见,我只添加了将实体演示为最小可行示例的字段。您可以根据需要随意添加更多内容。

class Employee(models.Model):
    employee_id = models.UUIDField(
        default=uuid.uuid4,
        primary_key=True,
        editable=False
    )
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)


class MeetingRoom(models.Model):
    room_id = models.UUIDField(
        default=uuid.uuid4,
        primary_key=True,
        editable=False
    )
    room_number = models.CharField(
        max_length=16,
        unique=True
    )

好的,现在让我们专注于预订实施。根据需求规范,员工应该能够进行预订,我们应该能够获取预订并按员工进行过滤。此外,预订需要员工在某个时间范围内在该房间组织会议,并且将有员工作为受邀者。这些受邀者可以选择接受或不接受邀请。跟踪受邀者是否接受邀请意味着我们还需要ManyToManyField 上的through 表。让我们为受邀者创建一个Reservation 模型和ManyToManyField 上的through 表。

class Reservation(models.Model):
    STATUS_VALID = 0
    STATUS_CANCELLED = 1
    STATUS_TYPES = [
        (STATUS_VALID, "Valid"),
        (STATUS_CANCELLED, "Cancelled"),
    ]

    meeting_id = models.UUIDField(
        default=uuid.uuid4,
        primary_key=True,
        editable=False
    )
    room = models.ForeignKey(
        MeetingRoom,
        related_name="reservations",
        on_delete=models.CASCADE
    )
    organizer = models.ForeignKey(
        Employee,
        related_name="organized_reservations",
        on_delete=models.CASCADE
    )
    invitees = models.ManyToManyField(
        Employee,
        through="ReservationInvitee"
    )
    title = models.CharField(max_length=150)
    status = models.IntegerField(
        choices=STATUS_TYPES,
        default=STATUS_VALID
    )
    date_from = models.DateTimeField()
    date_to = models.DateTimeField()


class ReservationInvitee(models.Model):
    IS_PENDING = -1
    IS_ATTENDING = 1
    IS_NOT_ATTENDING = 0
    ATTENDING_STATUSES = [
        (IS_PENDING, "Pending"),
        (IS_ATTENDING, "Attending"),
        (IS_NOT_ATTENDING, "Not attending")
    ]

    reservation = models.ForeignKey(
        Reservation,
        on_delete=models.CASCADE
    )
    employee = models.ForeignKey(
        Employee,
        related_name="invited_reservations",
        on_delete=models.CASCADE
    )
    status = models.IntegerField(
        choices=ATTENDING_STATUSES,
        default=IS_PENDING
    )

从这里开始,它为ReservationReservationInvitee 定义API 序列化程序和视图。我不会为EmployeeMeetingRoom 定义序列化程序和视图,因为它们对于这个实现并不重要。我会把它留给你做练习。

class ReservationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Reservation
        fields = (
            "meeting_id",
            "room",
            "organizer",
            "invitees",
            "title",
            "status",
            "date_from",
            "date_to",
        )
        read_only_fields = (
            "meeting_id",
            "invitees",
        )


class ReservationInviteeSerializer(serializers.ModelSerializer):
    class Meta:
        model = ReservationInvitee
        fields = "__all__"
        read_only_fields = ('id',)


class ReservationViewset(viewsets.ModelViewSet):
    queryset = Reservation.objects.all()
    serializer_class = ReservationSerializer


class ReservationInviteeViewset(viewsets.ModelViewSet):
    queryset = ReservationInvitee.objects.all()
    serializer_class = ReservationInviteeSerializer

现在,要通过 API 添加预订,您可以分两步完成:

    POST 数据到ReservationViewset。这假设您的数据库中已经有 EmployeeMeetingRoom 数据。成功发布数据后,响应将返回 meeting_id 以及您发布的其他字段值。 meeting_id 是您需要在第 2 步中发布的预订的 pk。 POST 数据到ReservationInviteeViewset,其中包括步骤 1 中自动生成的 meeting_id 的 pk 以及受邀者。将数据发布到此端点,以便邀请尽可能多的受邀者参加会议。

当受邀者接受/拒绝会议邀请时,您可以简单地将新有效负载 PUT/PATCH 放到 ReservationInviteeViewset 端点上。

现在是关于按员工过滤预订的问题,我假设是由组织会议的员工提出的。在这种情况下,您可以使用docs 中指定的过滤技术。我将通过query parameters as an example使用他们的过滤:

class ReservationViewset(viewsets.ModelViewSet):
    serializer_class = ReservationSerializer

    def get_queryset(self):
        queryset = Reservation.objects.all()
        employee = self.request.query_params.get('employee_id', None)
        if employee is not None:
            queryset = queryset.filter(organizer__employee_id=employee)
        return queryset

这对您来说应该是一个很好的起点。您仍然可以增强许多其他功能,例如显示ReservationSerializerReservationInvitee 详细信息。如果你想实现这一点,你可以阅读this post。其他增强功能包括验证date_fromdate_to 字段,以便它们不会与该会议室的其他预订冲突。这意味着您必须覆盖模型中的 cleansave 方法,或序列化程序中的 save 方法。

【讨论】:

我们可以继续聊天吗? chat.***.com/rooms/224820/dziugas 我想添加另一个选项,只允许组织者取消预订,方法是设置对象级权限。你可以看一个例子here

以上是关于Django:尝试使用保留创建会议室 API的主要内容,如果未能解决你的问题,请参考以下文章

使用 Google Meet API 发送会议 URL

使用 microsoft graph api c# 创建在线会议时出现 404 错误,但未登录 AzureActiveDirectory

通过 Lync api 创建只有一个用户的会议 - 立即开会

使用 UCWA API 安排 Lync 会议

将会议添加到活动 Google Calendar API

MS Graph API - 创建在线会议,不生成拨号会议信息。