【问题标题】:Django - distinct rows/objects distinguished by date/day from datetime fieldDjango - 以日期/日期与日期时间字段区分的不同行/对象
【发布时间】:2017-02-22 12:17:06
【问题描述】:

我已经搜索了很长时间,并且知道关于 sof 的几个答案,但即使我的问题很简单,也没有一个解决方案对我有用:

我需要什么(使用 postgres + django 1.10):我在日期时间字段中有很多行,其中包含许多重复日期(=天)。我想要一个每个日期/天包含一行/对象的查询集。

fk | col1 | colX | created (type: datetime)
----------------------------------------------
1  | info | info | 2016-09-03 08:25:52.142617+00:00 <- get it (time does not matter)
1  | info | info | 2016-09-03 16:26:52.142617+00:00
2  | info | info | 2016-09-03 11:25:52.142617+00:00
1  | info | info | 2016-09-14 16:26:52.142617+00:00 <- get it (time does not matter)
3  | info | info | 2016-09-14 11:25:52.142617+00:00
1  | info | info | 2016-09-25 23:25:52.142617+00:00 <- get it (time does not matter)
1  | info | info | 2016-09-25 16:26:52.142617+00:00
1  | info | info | 2016-09-25 11:25:52.142617+00:00
2  | info | info | 2016-09-25 14:27:52.142617+00:00
2  | info | info | 2016-09-25 16:26:52.142617+00:00
3  | info | info | 2016-09-25 11:25:52.142617+00:00
etc.

什么是最好的(性能 + pythionic/django)方法来做到这一点。我的模型/表格将有很多行(>百万)。

编辑 1

结果必须先用 fk 过滤(例如 WHERE fk = 1)。

我已经尝试过最明显的事情,例如

MyModel.objects.filter(fk=1).order_by('created__date').di‌​stinct('created__dat‌​e') 

但出现以下错误:

django.core.exceptions.FieldError:无法将关键字“日期”解析为字段。不允许加入“已创建”。

...all() 和通过 Meta 类而不是查询方法 order_by() 进行相应排序的相同错误...

在这种特定情况下,是否有人可能更了解此错误?

【问题讨论】:

    标签: python django postgresql datetime


    【解决方案1】:

    鉴于当前的 Django 实现,这似乎是不可能的,因为这将涉及使用高级 DB 后端功能(如 Postgres window functions)。

    你最接近的就是使用聚合:

    MyModel.objects.annotate(
        created_date=TruncDay('created')
    ).values('created_date').annotate(id=Min('id'))
    

    这将聚合相似的日期,并选择最小的 id。

    [{'created_date': datetime.date(2017, 3, 16), 'id': 146},
     {'created_date': datetime.date(2017, 3, 28), 'id': 188},
     {'created_date': datetime.date(2017, 3, 24), 'id': 178},
     {'created_date': datetime.date(2017, 3, 23), 'id': 171},
     {'created_date': datetime.date(2017, 3, 22), 'id': 157}] ...
    

    如果您需要整个对象,可以将其与 .values_list() 和另一个查询集链接起来,这将产生一个子查询:

    MyModel.objects.filter(
        id__in=MyModel.objects.annotate(
            created_date=TruncDay('created')
        ).values('created_date').annotate(id=Min('id')).values_list(
            'id', flat=True
        )
    )
    

    仅供参考,这会导致以下查询

    SELECT
        "myapp_mymodel"."id",
        "myapp_mymodel"."created",
        "myapp_mymodel"."col1",
        "myapp_mymodel"."colX"
    FROM "myapp_mymodel"
    WHERE "myapp_mymodel"."id" IN (
        SELECT MIN(U0."id") AS "id"
        FROM "myapp_mymodel" U0
        GROUP BY DATE(U0."created")
    )
    

    【讨论】:

      【解决方案2】:

      我刚刚遇到了类似的问题——不是order_by()distinct(),而是filter()。我使用的是 Django 1.9,但这在这里可能没有任何区别。

      在我的一个模型中的一个应用程序中,filter(datetime_field__date__lt=(date(2016, 12, 5))) 工作正常,在同一项目中不同应用程序的另一个模型中,我遇到了与您相同的错误。

      在我的情况下,似乎是django-money (https://github.com/django-money/django-money) 导致了问题。据我所知,djmoney.models.managers 中的 money_manager() 函数破坏了 __date 查找 (https://docs.djangoproject.com/en/1.9/ref/models/querysets/#date)。

      当我将另一个未命名为 objects 的经理(例如 testmanager = models.Manager())附加到相关模型而不将其包装在 money_manager() 中时,__date 查找再次正常工作,无需对模型或数据库。

      我还没有找到完全令人满意的解决方案,但也许您还使用django-money 或其他与默认管理器混淆的第三方应用程序?也许 traceback 给出了关于哪个包可能是问题的任何提示。

      我的回溯看起来像这样: Traceback (most recent call last): File "<input>", line 1, in <module> File "/[...]/python3.4/site-packages/django/db/models/manager.py", line 122, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/[...]/python3.4/site-packages/djmoney/models/managers.py", line 164, in wrapper args, kwargs = _expand_money_kwargs(model, args, kwargs, exclusions) File "/[...]/python3.4/site-packages/djmoney/models/managers.py", line 136, in _expand_money_kwargs elif isinstance(_get_field(model, name), MoneyField): File "/[...]/python3.4/site-packages/djmoney/models/managers.py", line 63, in _get_field field = qs.setup_joins(parts, opts, alias)[0] File "/[...]/python3.4/site-packages/django/db/models/sql/query.py", line 1405, in setup_joins names, opts, allow_many, fail_on_missing=True) File "/[...]/python3.4/site-packages/django/db/models/sql/query.py", line 1373, in names_to_path " not permitted." % (names[pos + 1], name)) django.core.exceptions.FieldError: Cannot resolve keyword 'date' into field. Join on 'my_datetime_field' not permitted.

      【讨论】:

      【解决方案3】:

      由于您使用的是 postgresql,因此您可以使用查询集通过创建值的不同来从表中获取结果。

      也许这样的查询应该可以完成工作:

      MyModel.objects.all().distinct('created__date')
      

      我也向你推荐 django 的查询集文档:https://docs.djangoproject.com/fr/1.10/ref/models/querysets/#distinct

      【讨论】:

      • 如果这能像我想的那样工作,不应该是.distinct('created__date') 吗?
      • 是的,没错,在帖子中没有看到“时间无关紧要”。答案已编辑。
      • ...这是最明显的解决方案之一,如果尝试出现以下错误:
      • 我的查询略有不同:
      • MyModel.objects.filter(xyz=123).order_by('created__date').distinct('created__date') django.core.exceptions.FieldError:无法将关键字“日期”解析为字段。不允许加入“已创建”。
      猜你喜欢
      • 2022-08-22
      • 2012-11-07
      • 1970-01-01
      • 2018-03-21
      • 1970-01-01
      • 1970-01-01
      • 2015-03-06
      • 2020-12-16
      • 2018-01-03
      相关资源
      最近更新 更多