【问题标题】:How to use multiple models inside one viewset/serializer?如何在一个视图集/序列化器中使用多个模型?
【发布时间】:2022-02-18 06:26:03
【问题描述】:

我的系统中有 2 个项目必须使用。但我正在尝试开发一个系统,我必须将它们放在一个视图中并按“时间戳”对它们进行排序。

class CalendarEventSerializer(serializers.ModelSerializer):

    class Meta:
        model = CalendarEvent
        fields = ("id","author",...)

class CalendarItemSerializer(serializers.ModelSerializer):

    class Meta:
        model = CalendarItem
        fields = ("id","author",...)

我使用 ViewSet 来调节我的模型以对其进行分页和过滤。

class CalendarItemViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,)
    queryset = CalendarItem.objects.all().order_by('-timestamp')
    serializer_class = CalendarItemSerializer
    filter_backends = [UserFilterBackend,DjangoFilterBackend]
    pagination_class = StandardResultsSetPagination
    filterset_fields = ['author']

class CalendarEventViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,)
    queryset = CalendarEvent.objects.all().order_by('-timestamp')
    serializer_class = CalendarEventSerializer
    filter_backends = [UserFilterBackend,DjangoFilterBackend]
    pagination_class = StandardResultsSetPagination
    filterset_fields = ['author']

我如何使用这个系统将 2 个或模型合并到一个视图集或序列化器中?

注意:我知道stackoverflow中有类似问题的一些答案,但我的代码结构不同,我想得到一些观点

更新

所以这就是我想要做的: - 我正在形成一个像 facebook/instagram 这样的提要页面,并在一个视图中组合多个模型。

-我已经可以使用上面的视图集了,但我现在想合并它们。

-我想按其时间戳对每个项目进行排序,并在 JSON 中检索它们,但在一个系统中检索它们,而不是像:

calendarevents:[] calendaritems []

但喜欢:

calendarevent 1(created 2 mins ago)
calendaritem 1 (created 3 mins ago)
calendarevent 2(created 4 mins ago) 
calendaritem 2(created 5 mins ago)

我很乐意提供更多信息,请尽管询问。

更新 2:

class CalendarEvent(models.Model):

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    author = models.ForeignKey(User,  on_delete=models.CASCADE,related_name='calendarevents')
    charfield1 = models.CharField(max_length=300)
    integerfield1 = models.IntegerField(default='0')
    charfield2 = models.CharField(max_length=200,null=True, blank=True)
    charfield3= models.CharField(null=True,blank=True,max_length=64000)

class CalendarItem(models.Model):


    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    author = models.ForeignKey(User,  on_delete=models.CASCADE,related_name='calendaritems')
    charfield1 = models.CharField(max_length=300)
    integerfield1 = models.IntegerField(default='0')
    charfield2 = models.CharField(max_length=200,null=True, blank=True)
    charfield3= models.CharField(null=True,blank=True,max_length=64000)


【问题讨论】:

  • 我从你的解释中得到的一件事是你想合并这两个 ModelViewSet。你能告诉我你想在什么基础上得到CalendarItemViewSet的结果,然后去显示CalendarEventViewSet的结果。
  • 如果你能告诉我条件基础,那么我们可以将它们自定义合并到模型视图集的辅助函数下。
  • 我已经更新了问题,请查看。
  • 如果是这种情况,我建议您编写自定义 APIView,因为模型视图集本质上应该用于单个模型。通过说我的意思是你可以做到,但定制模型视图集并获得结果作为两个模型的合并视图集结果并不是最佳实践。使用 APIView 集,您可以编写自定义 APIView,如果需要,您可以从 DRF 添加 Mxinins。
  • @BrianDestura 我无法分享模型的完整信息,但我给出了它们具有不同名称的公共字段。

标签: django django-rest-framework


【解决方案1】:

解决此问题的另一种方法是使用multi-table inheritance..[Django-doc]CalendarEventCalendarItem 创建父模型,其中可以在父模型中定义它们的公共字段:

class CalendarFeed(models.Model):
    author = models.ForeignKey(User,  on_delete=models.CASCADE,related_name='calendarevents')
    charfield1 = models.CharField(max_length=300)
    integerfield1 = models.IntegerField(default='0')
    charfield2 = models.CharField(max_length=200,null=True, blank=True)
    charfield3 = models.CharField(null=True,blank=True,max_length=64000)
    timestamp = models.DateTimeField(auto_now_add=True)


class CalendarEvent(CalendarFeed):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)


class CalendarItem(CalendarFeed):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

然后您可以创建一个序列化程序和一个捕获所有CalendarFeed 的视图集,如下所示:

class CalendarFeedSerializer(serializers.ModelSerializer):
    class Meta:
        model = CalendarFeed
        fields = "__all__"


class CalendarFeedViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,)
    queryset = CalendarFeed.objects.all().order_by('-timestamp')
    serializer_class = CalendarFeedSerializer
    filter_backends = [UserFilterBackend, DjangoFilterBackend]
    pagination_class = StandardResultsSetPagination
    filterset_fields = ['author']

使用这些,您可以通过父级CalendarFeed 列出所有CalendarEventCalendarItem

【讨论】:

  • django.core.exceptions.FieldError: Local field 'id' in class 'CalendarItem' clashes with field of the same name from base class 'CalendarFeed'.
  • 哦,是的,您可以将 id 移动到父级,或者添加另一个字段作为父链接,如多表继承的同一部分所述
【解决方案2】:

您可以使用 APIView 和通用 APIVIEW 自定义登录

这是实现目标的方法之一。

class GetCalenderEventAndItemsAPIView(APIView, GenericAPIView):
    permission_classes = (IsAuthenticated,)
    item_queryset = CalendarItem.objects.all().order_by('-timestamp')
    event_queryset = CalendarEvent.objects.all().order_by('-timestamp')
    item_serializer_class = CalendarItemSerializer
    event_serializer_class = CalendarEventSerializer
    filterset_fields = ['author']

    def get_paginated_query(self, _query_set):
        page = self.paginate_queryset(self.filter_queryset(_query_set))
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        return page

    def get(self, request, *args, **kwargs):
        event_serializer = self.event_serializer_class(self.get_paginated_query(self.event_queryset),
                                                       many=True)
        item_serializer = self.event_serializer_class(self.get_paginated_query(self.item_queryset), many=True)

        response_results = {
            "calendarevents": event_serializer.data,
            "calendaritems": item_serializer.data

        }
        return Response(response_results)

它会让你朝着正确的方向前进。随便玩一下上面的方法。

【讨论】:

  • GenericAPIView is not defined 这是我得到的错误
  • 请从 Django rest framework 导入 GenericAPIView from rest_framework.generics import GenericAPIView, and from rest_framework.views import APIView
  • TypeError: Cannot create a consistent method resolution order (MRO) for bases APIView, GenericAPIView
  • 如果 APIview 产生问题,您可以删除它
  • router.register(r'feedpage', GetCalendarEventAndItemsAPIView) 它现在给了我这个错误:assert queryset is not None, basename argument not specified, and could \ AssertionError: basename argument not specified, and could not automatically determine the name from the viewset,因为它没有`queryset 属性
猜你喜欢
  • 2017-02-08
  • 2014-07-05
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 2013-01-12
相关资源
最近更新 更多