Django按日期排序(天)

2hh7jdfx  于 2023-05-19  发布在  Go
关注(0)|答案(4)|浏览(126)

我想先按天排序模型,然后按分数排序,这意味着我想看到每天得分最高的文章。

class Article(models.Model):

date_modified = models.DateTimeField(blank=True, null=True)
score = models.DecimalField(max_digits=5, decimal_places=3, blank=True, null=True)

这个答案Django Datetime Field Query - Order by Time/Hour建议我将'__day'与我的date_modified一起使用,如下所示:

Article.objects.filter().order_by('-date_modified__day', '-score')
FieldError: Cannot resolve keyword 'day' into field. Join on 'date_modified' not permitted.

但是我得到了和帖子中相同的错误,所以我甚至不确定它应该以这种方式工作。
我使用.extra找到了其他答案django order by date in datetime / extract date from datetime

Article.objects.filter().extra(select={"day_mod": "strftime('%d', date_modified)"}, order_by=['-day_mod', '-score'])

这适用于没有其他条件的过滤,但是如果我在过滤器上应用一个条件,例如类别:

Article.objects.filter(category = 'Art').extra(select={'day_mod': "strftime('%d', date_modified)"}, order_by=['-day_mod', '-score'])

我得到这个错误:

File "/home/mykolas/anaconda2/lib/python2.7/site-packages/IPython/core/formatters.py", line 699, in __call__
printer.pretty(obj)

File "/home/mykolas/anaconda2/lib/python2.7/site-packages/IPython/lib/pretty.py", line 383, in pretty
return _default_pprint(obj, self, cycle)

File "/home/mykolas/anaconda2/lib/python2.7/site-packages/IPython/lib/pretty.py", line 503, in _default_pprint
_repr_pprint(obj, p, cycle)

File "/home/mykolas/anaconda2/lib/python2.7/site-packages/IPython/lib/pretty.py", line 694, in _repr_pprint
output = repr(obj)

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/models/query.py", line 234, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/models/query.py", line 258, in __iter__
self._fetch_all()

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/models/query.py", line 1074, in _fetch_all
self._result_cache = list(self.iterator())

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/models/query.py", line 52, in __iter__
results = compiler.execute_sql()

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 848, in execute_sql
cursor.execute(sql, params)

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/backends/utils.py", line 83, in execute
sql = self.db.ops.last_executed_query(self.cursor, sql, params)

File "/home/mykolas/lenv/lib/python2.7/site-packages/django/db/backends/sqlite3/operations.py", line 146, in last_executed_query
return sql % params

TypeError: %d format: a number is required, not unicode

我不知道这里发生了什么事,如果能帮忙就太好了。

bzzcjhmw

bzzcjhmw1#

from django.db.models import DateTimeField
from django.db.models.functions import Trunc

Article.objects.order_by(
    Trunc('date_modified', 'date', output_field=DateTimeField()).desc(),
    '-score')
  • Trunc()(Django 1.10)
  • order_by()
b4qexyjb

b4qexyjb2#

我想你应该使用标准的日期排序,没有额外的方法。格式处理是一个模板的责任。

Article.objects.filter(category='Art').order_by=('-date_modified', '-score')

然后在你的模板中,你可以用你想要的格式显示日期。我给你一个例子,查看API文档以获得更多选项。

{{ date_modified|date:"M/d"|lower }}

另一个例子(也许莫尔适合您的需要):

{{ date_modified|date:"D d M Y" }} {{ date_modified|time:"H:i" }}
xxb16uws

xxb16uws3#

如果你使用的是Django >= 1.8,你可以使用Func表达式。您遇到的问题是%符号被直接传递到数据库适配器,该适配器试图用相关参数替换%
你可以这样使用它:

from django.db.models import F, Func, Value

Article.objects.annotate(
    day_mod=Func(Value('%d'), F('date_modified'), 
    function='strftime'
).order_by('-day_mod', '-score')

这应该(理论上,我还没有测试过)以这样的SQL查询结束:

SELECT 
  ...
  strftime('%d', "article"."date_modified") AS "day_mod"
FROM "article"
  ...
ORDER BY "day_mod" DESC, "score" DESC

但是,我怀疑您需要将年份和月份添加到strftime中,否则您最终会发现月初的文章被前几个月结束时发生的旧文章所掩盖。
还应该注意的是,strftime函数不受MySQL或PostgreSQL支持。据我所知,它只受SQLite支持,不应该在生产中使用。
不幸的是,SQL中似乎没有一个日期时间格式的标准。MySQL似乎使用DATE_FORMAT(date, format),PostgreSQL使用to_char(date, format)
如果你想同时支持SQLite和另一个DB,你可以用相关的as_sqliteas_<db>方法编写一个自定义表达式来格式化你的日期时间,但这可能有点困难,因为不是所有的DB都使用相同的格式化字符串。
你最好的选择可能是将datetime转换为date,即。CAST (date_modified AS DATE)。这应该可以在大多数SQL中工作。我能想到的最简单的方法是:

from django.db.models import DateField, Expression, F

class CastToDate(Expression):
    template = 'CAST( %(expressions)s AS DATE )'

    def __init__(self, expressions, output_field=None, **extra):
        output_field = output_field or DateField()
        super(CastToDate, self).__init__(self, expressions, output_field, **extra)
        if len(expressions) != 1:
            raise ValueError('expressions must have exactly 1 element')

Articles.objects.annotate(
    day_mod=CastToDate(F('date_modified'))).order_by('-day_mod', '-score')
o8x7eapl

o8x7eapl4#

如果您使用DataTables

  • 在Article模型中添加属性:
@property
def convert_to_timestamp(self):
  return str(self.date_modified.timestamp())
  • 在HTML中,
<td data-order="{{ article.convert_to_timestamp }}"..

相关问题