diff -r 30c0963a57d4 django/db/backends/mysql/base.py
a
|
b
|
OPERATOR_MAPPING = {
|
228 | 228 | 'iexact': 'LIKE %s', |
229 | 229 | 'contains': 'LIKE BINARY %s', |
230 | 230 | 'icontains': 'LIKE %s', |
| 231 | 'regex': 'REGEXP BINARY %s', |
| 232 | 'iregex': 'REGEXP %s', |
231 | 233 | 'gt': '> %s', |
232 | 234 | 'gte': '>= %s', |
233 | 235 | 'lt': '< %s', |
diff -r 30c0963a57d4 django/db/backends/mysql_old/base.py
a
|
b
|
OPERATOR_MAPPING = {
|
229 | 229 | 'iexact': 'LIKE %s', |
230 | 230 | 'contains': 'LIKE BINARY %s', |
231 | 231 | 'icontains': 'LIKE %s', |
| 232 | 'regex': 'REGEXP BINARY %s', |
| 233 | 'iregex': 'REGEXP %s', |
232 | 234 | 'gt': '> %s', |
233 | 235 | 'gte': '>= %s', |
234 | 236 | 'lt': '< %s', |
diff -r 30c0963a57d4 django/db/backends/postgresql/base.py
a
|
b
|
OPERATOR_MAPPING = {
|
261 | 261 | 'iexact': 'ILIKE %s', |
262 | 262 | 'contains': 'LIKE %s', |
263 | 263 | 'icontains': 'ILIKE %s', |
| 264 | 'regex': '~ %s', |
| 265 | 'iregex': '~* %s', |
264 | 266 | 'gt': '> %s', |
265 | 267 | 'gte': '>= %s', |
266 | 268 | 'lt': '< %s', |
diff -r 30c0963a57d4 django/db/backends/postgresql_psycopg2/base.py
a
|
b
|
OPERATOR_MAPPING = {
|
206 | 206 | 'iexact': 'ILIKE %s', |
207 | 207 | 'contains': 'LIKE %s', |
208 | 208 | 'icontains': 'ILIKE %s', |
| 209 | 'regex': '~ %s', |
| 210 | 'iregex': '~* %s', |
209 | 211 | 'gt': '> %s', |
210 | 212 | 'gte': '>= %s', |
211 | 213 | 'lt': '< %s', |
diff -r 30c0963a57d4 django/db/backends/sqlite3/base.py
a
|
b
|
class DatabaseWrapper(local):
|
64 | 64 | } |
65 | 65 | kwargs.update(self.options) |
66 | 66 | self.connection = Database.connect(**kwargs) |
67 | | # Register extract and date_trunc functions. |
| 67 | # Register extract, date_trunc, and regexp functions. |
68 | 68 | self.connection.create_function("django_extract", 2, _sqlite_extract) |
69 | 69 | self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc) |
| 70 | self.connection.create_function("regexp", 2, _sqlite_regexp) |
70 | 71 | cursor = self.connection.cursor(factory=SQLiteCursorWrapper) |
71 | 72 | cursor.row_factory = utf8rowFactory |
72 | 73 | if settings.DEBUG: |
… |
… |
def get_sql_flush(style, tables, sequenc
|
164 | 165 | """Return a list of SQL statements required to remove all data from |
165 | 166 | all tables in the database (without actually removing the tables |
166 | 167 | themselves) and put the database in an empty 'initial' state |
167 | | |
| 168 | |
168 | 169 | """ |
169 | 170 | # NB: The generated SQL below is specific to SQLite |
170 | 171 | # Note: The DELETE FROM... SQL generated below works for SQLite databases |
… |
… |
def get_sql_sequence_reset(style, model_
|
182 | 183 | "Returns a list of the SQL statements to reset sequences for the given models." |
183 | 184 | # No sequence reset required |
184 | 185 | return [] |
185 | | |
| 186 | |
186 | 187 | def _sqlite_date_trunc(lookup_type, dt): |
187 | 188 | try: |
188 | 189 | dt = util.typecast_timestamp(dt) |
… |
… |
def _sqlite_date_trunc(lookup_type, dt):
|
195 | 196 | elif lookup_type == 'day': |
196 | 197 | return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day) |
197 | 198 | |
| 199 | def _sqlite_regexp(re_pattern, re_string): |
| 200 | import re |
| 201 | try: |
| 202 | return bool(re.search(re_pattern, re_string)) |
| 203 | except: |
| 204 | return False |
| 205 | |
198 | 206 | # SQLite requires LIKE statements to include an ESCAPE clause if the value |
199 | 207 | # being escaped has a percent or underscore in it. |
200 | 208 | # See http://www.sqlite.org/lang_expr.html for an explanation. |
… |
… |
OPERATOR_MAPPING = {
|
203 | 211 | 'iexact': "LIKE %s ESCAPE '\\'", |
204 | 212 | 'contains': "LIKE %s ESCAPE '\\'", |
205 | 213 | 'icontains': "LIKE %s ESCAPE '\\'", |
| 214 | 'regex': 'REGEXP %s', |
| 215 | 'iregex': "REGEXP '(?i)' || %s", |
206 | 216 | 'gt': '> %s', |
207 | 217 | 'gte': '>= %s', |
208 | 218 | 'lt': '< %s', |
diff -r 30c0963a57d4 django/db/models/fields/__init__.py
a
|
b
|
class Field(object):
|
169 | 169 | |
170 | 170 | def get_db_prep_lookup(self, lookup_type, value): |
171 | 171 | "Returns field's value prepared for database lookup." |
172 | | if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'): |
| 172 | if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'): |
173 | 173 | return [value] |
174 | 174 | elif lookup_type in ('range', 'in'): |
175 | 175 | return value |
diff -r 30c0963a57d4 django/db/models/query.py
a
|
b
|
QUERY_TERMS = (
|
20 | 20 | 'gt', 'gte', 'lt', 'lte', 'in', |
21 | 21 | 'startswith', 'istartswith', 'endswith', 'iendswith', |
22 | 22 | 'range', 'year', 'month', 'day', 'isnull', 'search', |
| 23 | 'regex', 'iregex', |
23 | 24 | ) |
24 | 25 | |
25 | 26 | # Size of each "chunk" for get_iterator calls. |
… |
… |
def get_where_clause(lookup_type, table_
|
748 | 749 | return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or '')) |
749 | 750 | elif lookup_type == 'search': |
750 | 751 | return backend.get_fulltext_search_sql(table_prefix + field_name) |
| 752 | elif lookup_type in ('regex', 'iregex'): |
| 753 | raise NotImplementedError |
751 | 754 | raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type) |
752 | 755 | |
753 | 756 | def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0): |
diff -r 30c0963a57d4 docs/db-api.txt
a
|
b
|
Note this is only available in MySQL and
|
1173 | 1173 | Note this is only available in MySQL and requires direct manipulation of the |
1174 | 1174 | database to add the full-text index. |
1175 | 1175 | |
| 1176 | regex |
| 1177 | ~~~~~ |
| 1178 | |
| 1179 | Case-sensitive regular expression match. |
| 1180 | |
| 1181 | The regular expression syntax is that of the database backend in use; for the |
| 1182 | ``sqlite`` backend, the syntax is that of Python's ``re`` module. |
| 1183 | |
| 1184 | Example:: |
| 1185 | |
| 1186 | Entry.objects.get(title__regex=r'^(An?|The) +') |
| 1187 | |
| 1188 | SQL equivalents:: |
| 1189 | |
| 1190 | SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL |
| 1191 | |
| 1192 | SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL |
| 1193 | |
| 1194 | SELECT ... WHERE title REGEXP '^(An?|The) +'; -- sqlite |
| 1195 | |
| 1196 | Using raw strings for passing in the regular expression syntax is recommended. |
| 1197 | |
| 1198 | Regular expression matching is not supported on the ``ado_mssql`` and |
| 1199 | ``oracle`` backends; these will raise a ``NotImplementedError``. |
| 1200 | |
| 1201 | iregex |
| 1202 | ~~~~~~ |
| 1203 | |
| 1204 | Case-insensitive regular expression match. |
| 1205 | |
| 1206 | Example:: |
| 1207 | |
| 1208 | Entry.objects.get(title__iregex=r'^(an?|the) +') |
| 1209 | |
| 1210 | SQL equivalents:: |
| 1211 | |
| 1212 | SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL |
| 1213 | |
| 1214 | SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL |
| 1215 | |
| 1216 | SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- sqlite |
| 1217 | |
1176 | 1218 | Default lookups are exact |
1177 | 1219 | ------------------------- |
1178 | 1220 | |