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
)
从这里开始,它为Reservation
和ReservationInvitee
定义API 序列化程序和视图。我不会为Employee
和MeetingRoom
定义序列化程序和视图,因为它们对于这个实现并不重要。我会把它留给你做练习。
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
。这假设您的数据库中已经有 Employee
和 MeetingRoom
数据。成功发布数据后,响应将返回 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
这对您来说应该是一个很好的起点。您仍然可以增强许多其他功能,例如显示ReservationSerializer
的ReservationInvitee
详细信息。如果你想实现这一点,你可以阅读this post。其他增强功能包括验证date_from
和date_to
字段,以便它们不会与该会议室的其他预订冲突。这意味着您必须覆盖模型中的 clean
或 save
方法,或序列化程序中的 save
方法。
【讨论】:
我们可以继续聊天吗? chat.***.com/rooms/224820/dziugas 我想添加另一个选项,只允许组织者取消预订,方法是设置对象级权限。你可以看一个例子here以上是关于Django:尝试使用保留创建会议室 API的主要内容,如果未能解决你的问题,请参考以下文章
使用 microsoft graph api c# 创建在线会议时出现 404 错误,但未登录 AzureActiveDirectory