1

以下是我的榜样

class Group(Log_Active_Owned_Model_Mixin):

    group_name = SafeCharField(max_length = 100, null=False, blank=False, sanitize_cb=safe_name_sanitizer)
    group_creator = ForeignKey(to=PSS_User, null=False, related_name="group_creator")
    members = ManyToManyField(to=PSS_User, through="GroupMemberShip", related_name="group_member")

    class Meta:
        ordering = ("Meta", )

    ## other methods also exists in this class.

class GroupMemberShip(Log_Active_Owned_Model_Mixin, ResolvableModelMixin):

    MEMBER_NONE     = 1
    MEMBER_ADMIN    = 2
    MEMBER_STANDARD = 4


    VALID_MEMBERSHIPS = (
        (MEMBER_ADMIN,      "Admin"     ),
        (MEMBER_STANDARD,   "Standard"  ),
        (MEMBER_NONE,       "None"      )
    )

    member  = ForeignKey(to=PSS_User, null=False, related_name="groups")
    group   = ForeignKey(to=Group, null=False, related_name="members")
    membership_type     = SmallIntegerField(editable=False, null=False, blank=False, choices=VALID_MEMBERSHIPS)
    membership_request  = ForeignKey(to=GroupMemberShipRequest, null=True, blank=True)  # null True for group creator

    class Meta:
        ordering = ("date_created")
        unique_together = ("member", "group")

    ## other methods also exists in this class.

class GroupMemberShipRequest(Log_Active_Owned_Model_Mixin):

    GRP_MEMBERSHIP_REQ_STATUS_ACCEPTED  = 1
    GRP_MEMBERSHIP_REQ_STATUS_REJECTED  = 2
    GRP_MEMBERSHIP_REQ_STATUS_PENDING   = 4

    VALID_REQUEST_STATUSES = (
        (GRP_MEMBERSHIP_REQ_STATUS_ACCEPTED,    "Accepted"),
        (GRP_MEMBERSHIP_REQ_STATUS_REJECTED,    "Rejected"),
        (GRP_MEMBERSHIP_REQ_STATUS_PENDING,     "Pending")
    )

    #   TODO :-
    #   Add a field in request-type. There are two types of requests :-
    #   User can request admin to include him in the request.
    #   Admin can request other user, to become part of given group.

    GRP_REQUEST_ACTIVE  = 1
    GRP_REQUEST_PASSIVE = 2

    VALID_GRP_REQUESTS = (
        (GRP_REQUEST_ACTIVE,    "Active"),
        (GRP_REQUEST_PASSIVE,   "Passive")
    )

    request_initiator = ForeignKey(to=PSS_User, null=False, blank=False)
    request_acceptor_rejector = ForeignKey(to=PSS_User, null=True, blank=False)
    request_status  = SmallIntegerField(null=False, editable=False, choices=VALID_REQUEST_STATUSES, default=GRP_MEMBERSHIP_REQ_STATUS_PENDING)
    target_group = ForeignKey(to=Group, null=False, blank=False, related_name="members")
    request_type = SmallIntegerField(null=False, editable=False, default=GRP_REQUEST_ACTIVE, choices=VALID_GRP_REQUESTS)

现在以下是不同类型的操作,可以使用此 Group 模型:-

  • 创建组
  • 更新组
    1. 更新群组详情。
    2. 添加/删除组成员
    3. 向外人发送邀请
    4. 使管理员/删除管理员。
      • 删除组

对于创建/删除操作,事情很清楚,但我对更新操作感到困惑,因为可以更新很多东西。目前,我在 Group 类中添加了辅助方法,它完成了上述所有活动。

我的问题是,如何将它与 DRF(Django Rest Framework) ModelViewSets 集成。由于只有一个 update() 方法,它只能服务于上述更新场景之一。我该如何处理其他更新场景?(一个可能的解决方案,我认为是在请求中使用操作类型标志并在 update() 方法中检查它来决定调用哪个模型方法,但这有点幼稚的解决方案。有没有更好的在 Django Rest Framework 中执行此操作的方法?)

提前致谢。

4

1 回答 1

1

考虑这篇文章设计实用 RESTful API 的最佳实践

将其视为具有 RESTful 原则的子资源。例如,GitHub 的 API 允许您使用 PUT /gists/:id/star 为 gist 加星标,并使用 DELETE /gists/:id/star 取消星标。

在您的情况下,一个组有 4 种不同的操作。我在 DRF 中看到了两种解决方法。按照上面的提示,您可以使用@detail_route装饰器:

from rest_framework.decorators import detail_route

class GroupViewSet(viewsets.ModelViewset):

    @detail_route(methods=['put', 'delete'])
    def send_invite(self, request, pk=None):
        # check for the method provided 
        # do your logic and return a Response object
        pass

它将向视图集路由器添加额外的端点,该端点位于详细信息页面之后

/api/groups/:id/send_invite/

它适用于简单的任务。但是当你需要一个复杂的嵌套逻辑时,你可能会发现这个包drf-nested-routers很有用。它允许您在彼此之上构建视图。

/api/groups/:id/admin/:id/

但有时它是矫枉过正的,它违反了设计 API 的最佳实践

于 2017-01-31T09:32:46.337 回答