Code

Ticket #7672: dayofweek_filter.r7875.v4.diff

File dayofweek_filter.r7875.v4.diff, 7.6 KB (added by rossp, 6 years ago)

Fixed indentation, now works in sqlite3, postgres and mysql. Oracle untested.

Line 
1Index: django/db/models/sql/where.py
2===================================================================
3--- django/db/models/sql/where.py       (revision 7875)
4+++ django/db/models/sql/where.py       (working copy)
5@@ -152,7 +152,7 @@
6                     params)
7         elif lookup_type in ('range', 'year'):
8             return ('%s BETWEEN %%s and %%s' % field_sql, params)
9-        elif lookup_type in ('month', 'day'):
10+        elif lookup_type in ('month', 'day', 'week_day'):
11             return ('%s = %%s' % connection.ops.date_extract_sql(lookup_type,
12                     field_sql), params)
13         elif lookup_type == 'isnull':
14Index: django/db/models/sql/constants.py
15===================================================================
16--- django/db/models/sql/constants.py   (revision 7875)
17+++ django/db/models/sql/constants.py   (working copy)
18@@ -4,7 +4,7 @@
19 QUERY_TERMS = dict([(x, None) for x in (
20     'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
21     'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
22-    'month', 'day', 'isnull', 'search', 'regex', 'iregex',
23+    'month', 'day', 'week_day', 'isnull', 'search', 'regex', 'iregex',
24     )])
25
26 # Size of each "chunk" for get_iterator calls.
27Index: django/db/models/fields/__init__.py
28===================================================================
29--- django/db/models/fields/__init__.py (revision 7875)
30+++ django/db/models/fields/__init__.py (working copy)
31@@ -233,7 +233,7 @@
32         if hasattr(value, 'as_sql'):
33             sql, params = value.as_sql()
34             return QueryWrapper(('(%s)' % sql), params)
35-        if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'):
36+        if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'week_day', 'search'):
37             return [value]
38         elif lookup_type in ('range', 'in'):
39             return value
40Index: django/db/backends/postgresql/operations.py
41===================================================================
42--- django/db/backends/postgresql/operations.py (revision 7875)
43+++ django/db/backends/postgresql/operations.py (working copy)
44@@ -26,7 +26,12 @@
45
46     def date_extract_sql(self, lookup_type, field_name):
47         # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
48-        return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
49+        if lookup_type == 'week_day':
50+            # Using EXTRACT(), PostgreSQL days are indexed as Sunday=0, Saturday=6.
51+            # If we instead us TO_CHAR, they're indexed with Sunday=1, Saturday=7
52+            return "TO_CHAR(%s, 'D')" % field_name
53+        else:
54+            return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
55
56     def date_trunc_sql(self, lookup_type, field_name):
57         # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
58Index: django/db/backends/sqlite3/base.py
59===================================================================
60--- django/db/backends/sqlite3/base.py  (revision 7875)
61+++ django/db/backends/sqlite3/base.py  (working copy)
62@@ -151,7 +151,10 @@
63         dt = util.typecast_timestamp(dt)
64     except (ValueError, TypeError):
65         return None
66-    return str(getattr(dt, lookup_type))
67+    if lookup_type == 'week_day':
68+        return str((dt.isoweekday() % 7) + 1)
69+    else:
70+        return str(getattr(dt, lookup_type))
71
72 def _sqlite_date_trunc(lookup_type, dt):
73     try:
74Index: django/db/backends/mysql/base.py
75===================================================================
76--- django/db/backends/mysql/base.py    (revision 7875)
77+++ django/db/backends/mysql/base.py    (working copy)
78@@ -68,7 +68,12 @@
79 class DatabaseOperations(BaseDatabaseOperations):
80     def date_extract_sql(self, lookup_type, field_name):
81         # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
82-        return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
83+        if lookup_type == 'week_day':
84+            # DAYOFWEEK() returns an integer, 1-7, Sunday=1.
85+            # Note: WEEKDAY() returns 0-6, Monday=0.
86+            return "DAYOFWEEK(%s)" % field_name
87+        else:
88+            return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
89
90     def date_trunc_sql(self, lookup_type, field_name):
91         fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
92Index: django/db/backends/oracle/base.py
93===================================================================
94--- django/db/backends/oracle/base.py   (revision 7875)
95+++ django/db/backends/oracle/base.py   (working copy)
96@@ -56,7 +56,11 @@
97
98     def date_extract_sql(self, lookup_type, field_name):
99         # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
100-        return "EXTRACT(%s FROM %s)" % (lookup_type, field_name)
101+        if lookup_type == 'week_day':
102+            # TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday.
103+            return "TO_CHAR(%s, 'D')" % field_name
104+        else:
105+            return "EXTRACT(%s FROM %s)" % (lookup_type, field_name)
106
107     def date_trunc_sql(self, lookup_type, field_name):
108         # Oracle uses TRUNC() for both dates and numbers.
109Index: tests/modeltests/basic/models.py
110===================================================================
111--- tests/modeltests/basic/models.py    (revision 7875)
112+++ tests/modeltests/basic/models.py    (working copy)
113@@ -68,6 +68,8 @@
114 <Article: Area woman programs in Python>
115 >>> Article.objects.get(pub_date__year=2005, pub_date__month=7, pub_date__day=28)
116 <Article: Area woman programs in Python>
117+>>> Article.objects.get(pub_date__week_day=5)
118+<Article: Area woman programs in Python>
119
120 # The "__exact" lookup type can be omitted, as a shortcut.
121 >>> Article.objects.get(id=1)
122@@ -82,6 +84,11 @@
123 >>> Article.objects.filter(pub_date__year=2005, pub_date__month=7)
124 [<Article: Area woman programs in Python>]
125
126+>>> Article.objects.filter(pub_date__week_day=5)
127+[<Article: Area woman programs in Python>]
128+>>> Article.objects.filter(pub_date__week_day=6)
129+[]
130+
131 # Django raises an Article.DoesNotExist exception for get() if the parameters
132 # don't match any object.
133 >>> Article.objects.get(id__exact=2)
134@@ -94,6 +101,11 @@
135     ...
136 DoesNotExist: Article matching query does not exist.
137
138+>>> Article.objects.get(pub_date__week_day=6)
139+Traceback (most recent call last):
140+    ...
141+DoesNotExist: Article matching query does not exist.
142+
143 # Lookup by a primary key is the most common case, so Django provides a
144 # shortcut for primary-key exact lookups.
145 # The following is identical to articles.get(id=1).
146Index: docs/db-api.txt
147===================================================================
148--- docs/db-api.txt     (revision 7875)
149+++ docs/db-api.txt     (working copy)
150@@ -1534,6 +1534,25 @@
151 Note this will match any record with a pub_date on the third day of the month,
152 such as January 3, July 3, etc.
153
154+week_day
155+~~~~~~~~
156+
157+For date/datetime fields, a 'day of the week' match.
158+
159+Example::
160+
161+    Entry.objects.filter(pub_date__week_day=2)
162+
163+SQL equivalent::
164+
165+    SELECT ... WHERE EXTRACT('dow' FROM pub_date) = '2';
166+
167+(The exact SQL syntax varies for each database engine.)
168+
169+Note this will match any record with a pub_date that falls on a Tuesday (day 2
170+of the week), regardless of the month or year in which it occurs. Week days
171+are zero-indexed, with day 0 being Sunday and day 6 being Saturday.
172+
173 isnull
174 ~~~~~~