【问题标题】:Django: aggregate or annotate function, flatten JSON and filter dataDjango:聚合或注释函数,展平 JSON 和过滤数据
【发布时间】:2021-10-05 08:55:42
【问题描述】:

解决方案简单易行,但我无法获取我想要的东西。我正在尝试获取摘要一个具有外键主键关系并提供嵌套 JSON 数据数组的摘要表,这些数据很难在前端以表格格式显示。所以我试图在后端将其展平,添加过滤器并相应地获取。

我的方法是错误的,如果有人可以帮忙,我很感激。

model.py

class Place(models.Model):
    id = models.IntegerField(primary_key=True)
    location = models.CharField(max_length=100)

    class Meta:
        db_table = 'place'
        managed=False
        
        
class Session(models.Model):
    id = models.IntegerField(primary_key=True)
    place = models.ForeignKey(Place,related_name='session',on_delete=models.CASCADE, null=True)
    start = models.DateField(auto_now=True)
    count = models.IntegerField()
    num_not_placed = models.IntegerField()

    class Meta:
        db_table = 'session'
        managed=False


class Animal(models.Model):
    id = models.IntegerField(primary_key=True)
    sess = models.ForeignKey(Session,related_name='details',on_delete=models.CASCADE, null=True)
    type = models.CharField(max_length=100)
    is_active = models.BooleanField()
    length = models.DecimalField(max_digits=6, decimal_places=2)


    class Meta:
        db_table = 'animal'
        managed=False

serializers.py

class PlaceSerializer(FlexFieldsModelSerializer):
  length_max = serializers.DecimalField(max_digits=10, decimal_places=2)
  length_min = serializers.DecimalField(max_digits=10, decimal_places=2)
  length_avg = serializers.DecimalField(max_digits=10, decimal_places=2)
  length_std = serializers.DecimalField(max_digits=10, decimal_places=2)
  is_active_percent = serializers.IntegerField()
  counts = serializers.IntegerField()
  Num_of_not_placed = serializers.IntegerField()
  Date = serializers.DateField()
  type = serializers.CharField()
  class Meta:
      model = place
      fields = ["Date","location","type","is_active_percent","length_max","length_min","length_avg","length_std","Num_of_not_placed","counts"]
      expandable_fields = {
        'session': (SessionSerializer, {'many': True})
      }

我使用了弹性域序列化程序,当我尝试展开时它不起作用。

views.py

class SummaryFilter(FilterSet):
    type_filter = filters.CharFilter(method="filter_by_type")

    def filter_by_type(self,queryset,name,value):
        queryset = Place.objects.prefetch_related(
            Prefetch('session', queryset=Countsession.objects.filter(details__type=value).distinct()),
            Prefetch('session__details', queryset=Lifeform.objects.filter(type=value).order_by('id').distinct()),)
        return queryset

class SummaryModelViewSet(ModelViewSet):
    queryset = Place.objects.all().filter(session__details__type='shrimps')
    serializer_class = PlaceSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_class = SummaryFilter

    def get_queryset(self):
        queryset = Place.objects.values('location','session__start').annotate(total_count=Count('session__details__deformed'), def_count = Count('session__details__deformed',filter=Q(session__details__deformed=True))).values('location','session__start',def_percent = F('def_count')/F('total_count')*100).annotate(            
            counts = Count('session__details__deformed'),
            length_max=Max('session__details__length'),
            length_min=Min('session__details__length'),
            length_avg=Avg('session__details__length'),
            length_std=StdDev('session__details__length'),
            Num_of_not_placed = Sum('session__num_not_sortable'),
            Date = TruncDate('session__start'),
            type = F('session__details__type')
        )

        return queryset

我目前正在像这样将 JSON 格式展平

[
    {
        "Date": "2021-01-01",
        "location": "Loc 1",
        "type": "dog",
        "is_active_percent": 40,
        "length_max": "38.74",
        "length_min": "22.46",
        "length_avg": "35.48",
        "length_std": "6.51",
        "Num_of_not_placed": 0,
        "counts": 5
    },
    {
        "Date": "2021-01-02",
        "location": "Loc 1",
        "type": "dog",
        "is_active_percent": 50,
        "length_max": "43.47",
        "length_min": "43.47",
        "length_avg": "43.47",
        "length_std": "0.00",
        "Num_of_not_placed": 0,
        "counts": 4
    },
    {
        "Date": "2021-01-01",
        "location": "Loc 2",
        "type": "cat",
        "is_active_percent": 50,
        "length_max": "38.74",
        "length_min": "38.74",
        "length_avg": "38.74",
        "length_std": "0.00",
        "Num_of_not_placed": 0,
        "counts": 4
    },
    {
        "Date": "2021-01-03",
        "location": "Loc 2",
        "type": "cat",
        "is_active_percent": 0,
        "length_max": "24.45",
        "length_min": "24.45",
        "length_avg": "24.45",
        "length_std": "0.00",
        "Num_of_not_placed": 0,
        "counts": 4
    }
]

我无法使用 API 进行扩展或过滤,当我尝试使用基于自定义的过滤器时,我收到一条错误消息,提示 尝试在序列化程序 PlaceSerializer 上获取字段 Date 的值。序列化程序字段可能命名不正确,并且与 Place 实例上的任何属性或键都不匹配。原始异常文本是:“地点”对象没有属性“日期”。 但我已将 Date 列定义为 Serialisers 列。我正在尝试根据位置和日期(每天、每周、每月、每年)分别和一起在 api 中发送的类型和分组进行过滤。

【问题讨论】:

  • Tank 模型是否有 Date 字段?如果不是,您需要告诉序列化程序如何获取此字段
  • 日期、类型、Num_of_not_placed 和我在序列化程序级别定义为字段并取自视图的其他字段。在此之后,我什至无法根据类型进行扩展或过滤。
  • @bdbd,任何建议或解决方案,如何检索?
  • Tank 型号是什么?
  • Place 模型只是 Tank 模型。我已经编辑了代码。

标签: django django-models django-rest-framework django-views django-forms


【解决方案1】:

Filterset 采用模型,因此您可以将 Datefield 添加到您的 Place 模型中,并使用这样的过滤器集

class PlaceFilter(FilterSet):
class Meta:
    model = Place
    fields = {
        'Date': ['exact', 'range', 'in'],
        }

旁注:

  1. Django 自动为模型提供 id 字段,您不必显式添加它
  2. 表名也是如此,除非出于某种原因您希望表名与模型名不同
  3. 在模型中指定所有字段然后使用上面的 ModelSerializer 和 Filterset 等类要容易得多

干杯!万事如意!

【讨论】:

  • 上述过滤器不起作用。日期和类型字段是序列化器字段。这不能用作元中的字段。 TypeError: 'Meta.fields' must not contain non-model field names: Date出现上述错误。
  • 为什么不能将它们用作模型字段然后像上面那样过滤?这是我的建议
  • 因为这些字段来自会话和动物模型。从嵌套的 JSON 中获取数据很困难,所以我将其展平,使用注释并将其保存在序列化器列中。
猜你喜欢
  • 1970-01-01
  • 2011-07-07
  • 2015-01-25
  • 1970-01-01
  • 2015-12-29
  • 2016-01-30
  • 2016-11-18
  • 2023-03-13
  • 2019-07-01
相关资源
最近更新 更多