我想先按天分类,然后按分数分类,这意味着我希望每天都能看到得分最高的文章。
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
不知道这里发生了什么,帮助将不胜感激。
答案 0 :(得分:4)
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()
答案 1 :(得分:2)
如果你正在使用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
,否则您最终会在月初被旧文章埋葬的文章发生在前几个月末。
还应该注意MySQL或PostgreSQL不支持strftime
函数。据我所知,只有SQLite支持它,不应该在生产中使用。
不幸的是,它似乎不是SQL中日期时间格式的标准。 MySQL似乎使用DATE_FORMAT(date, format)
而PostgreSQL使用to_char(date, format)
。
如果您想同时支持SQLite和其他数据库,您可以write a custom expression使用相关的as_sqlite
和as_<db>
方法来格式化您的日期时间,但这可能有点困难,因为并非所有数据库都使用相同的格式化字符串。
您最好的选择可能就是将日期时间转换为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')
答案 2 :(得分:1)
我猜您应该使用标准日期排序,而无需额外的方法。格式处理是模板的责任。
PUB/SUB
然后在您的模板中,您可以以所需的格式显示日期。我给您举个例子,请参阅more options的api文档。
MetaTrader Terminal
另一个例子(也许适合你的需求):
MQL4