django-find 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_find-1.0.1/.gitignore +6 -0
- django_find-1.0.1/LICENSE +17 -0
- django_find-1.0.1/PKG-INFO +137 -0
- django_find-1.0.1/README.md +102 -0
- django_find-1.0.1/django_find/__init__.py +4 -0
- django_find-1.0.1/django_find/apps.py +5 -0
- django_find-1.0.1/django_find/dom.py +127 -0
- django_find-1.0.1/django_find/handlers.py +75 -0
- django_find-1.0.1/django_find/model_helpers.py +14 -0
- django_find-1.0.1/django_find/models.py +361 -0
- django_find-1.0.1/django_find/parsers/__init__.py +0 -0
- django_find-1.0.1/django_find/parsers/json.py +64 -0
- django_find-1.0.1/django_find/parsers/parser.py +31 -0
- django_find-1.0.1/django_find/parsers/query.py +198 -0
- django_find-1.0.1/django_find/rawquery.py +78 -0
- django_find-1.0.1/django_find/refs.py +260 -0
- django_find-1.0.1/django_find/serializers/__init__.py +0 -0
- django_find-1.0.1/django_find/serializers/django.py +105 -0
- django_find-1.0.1/django_find/serializers/serializer.py +11 -0
- django_find-1.0.1/django_find/serializers/sql.py +210 -0
- django_find-1.0.1/django_find/serializers/util.py +15 -0
- django_find-1.0.1/django_find/templates/django_find/form.html +8 -0
- django_find-1.0.1/django_find/templates/django_find/headers.html +3 -0
- django_find-1.0.1/django_find/templatetags/__init__.py +0 -0
- django_find-1.0.1/django_find/templatetags/find_tags.py +35 -0
- django_find-1.0.1/django_find/tree.py +43 -0
- django_find-1.0.1/django_find/urls.py +7 -0
- django_find-1.0.1/django_find/version.py +5 -0
- django_find-1.0.1/pyproject.toml +70 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
3
|
+
in the Software without restriction, including without limitation the rights
|
|
4
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
5
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
6
|
+
furnished to do so, subject to the following conditions:
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all
|
|
9
|
+
copies or substantial portions of the Software.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
12
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
14
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
15
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
16
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
17
|
+
SOFTWARE.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-find
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Simple but powerful search/filter functionality for Django projects
|
|
5
|
+
Project-URL: Homepage, https://github.com/knipknap/django-find
|
|
6
|
+
Project-URL: Repository, https://github.com/knipknap/django-find
|
|
7
|
+
Project-URL: Issues, https://github.com/knipknap/django-find/issues
|
|
8
|
+
Author-email: Samuel Abels <knipknap@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: django,filter,find,json,query,search,sql
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Web Environment
|
|
14
|
+
Classifier: Framework :: Django
|
|
15
|
+
Classifier: Framework :: Django :: 4.2
|
|
16
|
+
Classifier: Framework :: Django :: 5.1
|
|
17
|
+
Classifier: Framework :: Django :: 5.2
|
|
18
|
+
Classifier: Framework :: Django :: 6.0
|
|
19
|
+
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Classifier: Programming Language :: Python
|
|
23
|
+
Classifier: Programming Language :: Python :: 3
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
28
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
29
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
30
|
+
Classifier: Topic :: Text Processing :: Filters
|
|
31
|
+
Requires-Python: >=3.10
|
|
32
|
+
Requires-Dist: dateparser
|
|
33
|
+
Requires-Dist: django>=4.2
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# django-find
|
|
37
|
+
|
|
38
|
+
[](https://travis-ci.org/knipknap/django-find)
|
|
39
|
+
[](https://coveralls.io/github/knipknap/django-find?branch=master)
|
|
40
|
+
[](https://lima.codeclimate.com/github/knipknap/django-find)
|
|
41
|
+
[](http://django-find.readthedocs.io/en/latest/?badge=latest)
|
|
42
|
+
|
|
43
|
+
## Summary
|
|
44
|
+
|
|
45
|
+
**django-find** is a Django app that makes it easy to add complex
|
|
46
|
+
search/filter functionality for the models in your project.
|
|
47
|
+
It supports two different ways to search your Django models:
|
|
48
|
+
Query-based, or JSON-based.
|
|
49
|
+
|
|
50
|
+
**django-find** is not a full text search engine, it searches the fields
|
|
51
|
+
of your models. In other words, it filters on your models and provides
|
|
52
|
+
tabular data as a result.
|
|
53
|
+
|
|
54
|
+
## Features
|
|
55
|
+
|
|
56
|
+
### Query-based search
|
|
57
|
+
|
|
58
|
+
By query-based, we mean that you can use statements like these
|
|
59
|
+
to search your models:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
author:"robert frost" and (title:road or chapter:2)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Add a search field to your template using a single tag
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
{% load find_tags %}
|
|
69
|
+
{% find object_list %}
|
|
70
|
+
{% for obj in object_list %}
|
|
71
|
+
{{ obj.name }}
|
|
72
|
+
{% endfor %}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
(object\_list is a queryset that is passed to the template)
|
|
76
|
+
|
|
77
|
+
### Query in your code
|
|
78
|
+
|
|
79
|
+
Just add the Searchable mixin:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from django_find import Searchable
|
|
83
|
+
|
|
84
|
+
class Author(models.Model, Searchable):
|
|
85
|
+
name = models.CharField("Author Name", max_length=10)
|
|
86
|
+
...
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
And you are good to go:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Query-based search returns a standard Django QuerySet that you
|
|
93
|
+
# can .filter() and work with as usual.
|
|
94
|
+
query = Book.by_query('author:"robert frost" and title:"the road"')
|
|
95
|
+
|
|
96
|
+
# You can also get a Django Q object for the statements.
|
|
97
|
+
q_obj = Book.q_from_query('author:"robert frost" and title:"the road"')
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Query using JSON
|
|
101
|
+
|
|
102
|
+
To make it easy to do complex searches spanning multiple models, JSON-based
|
|
103
|
+
query method is provided. It allows your to make custom searches like these:
|
|
104
|
+
|
|
105
|
+

|
|
106
|
+
|
|
107
|
+
For this, a JSON-based search functionality is provided:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
{
|
|
111
|
+
"Author":{"name":[[["equals","test"]]]},
|
|
112
|
+
"Book": {"title":[[["notcontains","c"]]]},
|
|
113
|
+
"Chapter": {"content":[[["startswith","The "]]]}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
django-find is smart in figuring out how to join those models
|
|
118
|
+
together and return a useful result.
|
|
119
|
+
In your code, you can load the JSON and get back the search
|
|
120
|
+
result:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# JSON-based search exhausts what Django's ORM can do, so it does
|
|
124
|
+
# not return a Django QuerySet, but a row-based PaginatedRawQuerySet:
|
|
125
|
+
query, field_list = Book.by_json_raw('''{
|
|
126
|
+
"Chapter": {"title":[[["contains","foo"]]]}
|
|
127
|
+
}''')
|
|
128
|
+
print('|'.join(field_list))
|
|
129
|
+
for row in query:
|
|
130
|
+
print('|'.join(row))
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Documentation
|
|
134
|
+
|
|
135
|
+
Full documentation, including installation instructions, is here:
|
|
136
|
+
|
|
137
|
+
http://django-find.readthedocs.io
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# django-find
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/knipknap/django-find)
|
|
4
|
+
[](https://coveralls.io/github/knipknap/django-find?branch=master)
|
|
5
|
+
[](https://lima.codeclimate.com/github/knipknap/django-find)
|
|
6
|
+
[](http://django-find.readthedocs.io/en/latest/?badge=latest)
|
|
7
|
+
|
|
8
|
+
## Summary
|
|
9
|
+
|
|
10
|
+
**django-find** is a Django app that makes it easy to add complex
|
|
11
|
+
search/filter functionality for the models in your project.
|
|
12
|
+
It supports two different ways to search your Django models:
|
|
13
|
+
Query-based, or JSON-based.
|
|
14
|
+
|
|
15
|
+
**django-find** is not a full text search engine, it searches the fields
|
|
16
|
+
of your models. In other words, it filters on your models and provides
|
|
17
|
+
tabular data as a result.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
### Query-based search
|
|
22
|
+
|
|
23
|
+
By query-based, we mean that you can use statements like these
|
|
24
|
+
to search your models:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
author:"robert frost" and (title:road or chapter:2)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Add a search field to your template using a single tag
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
{% load find_tags %}
|
|
34
|
+
{% find object_list %}
|
|
35
|
+
{% for obj in object_list %}
|
|
36
|
+
{{ obj.name }}
|
|
37
|
+
{% endfor %}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
(object\_list is a queryset that is passed to the template)
|
|
41
|
+
|
|
42
|
+
### Query in your code
|
|
43
|
+
|
|
44
|
+
Just add the Searchable mixin:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from django_find import Searchable
|
|
48
|
+
|
|
49
|
+
class Author(models.Model, Searchable):
|
|
50
|
+
name = models.CharField("Author Name", max_length=10)
|
|
51
|
+
...
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
And you are good to go:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
# Query-based search returns a standard Django QuerySet that you
|
|
58
|
+
# can .filter() and work with as usual.
|
|
59
|
+
query = Book.by_query('author:"robert frost" and title:"the road"')
|
|
60
|
+
|
|
61
|
+
# You can also get a Django Q object for the statements.
|
|
62
|
+
q_obj = Book.q_from_query('author:"robert frost" and title:"the road"')
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Query using JSON
|
|
66
|
+
|
|
67
|
+
To make it easy to do complex searches spanning multiple models, JSON-based
|
|
68
|
+
query method is provided. It allows your to make custom searches like these:
|
|
69
|
+
|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
For this, a JSON-based search functionality is provided:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
{
|
|
76
|
+
"Author":{"name":[[["equals","test"]]]},
|
|
77
|
+
"Book": {"title":[[["notcontains","c"]]]},
|
|
78
|
+
"Chapter": {"content":[[["startswith","The "]]]}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
django-find is smart in figuring out how to join those models
|
|
83
|
+
together and return a useful result.
|
|
84
|
+
In your code, you can load the JSON and get back the search
|
|
85
|
+
result:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# JSON-based search exhausts what Django's ORM can do, so it does
|
|
89
|
+
# not return a Django QuerySet, but a row-based PaginatedRawQuerySet:
|
|
90
|
+
query, field_list = Book.by_json_raw('''{
|
|
91
|
+
"Chapter": {"title":[[["contains","foo"]]]}
|
|
92
|
+
}''')
|
|
93
|
+
print('|'.join(field_list))
|
|
94
|
+
for row in query:
|
|
95
|
+
print('|'.join(row))
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
Full documentation, including installation instructions, is here:
|
|
101
|
+
|
|
102
|
+
http://django-find.readthedocs.io
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from builtins import str
|
|
2
|
+
from .tree import Node
|
|
3
|
+
|
|
4
|
+
operators = [
|
|
5
|
+
'contains',
|
|
6
|
+
'equals',
|
|
7
|
+
'startswith',
|
|
8
|
+
'endswith',
|
|
9
|
+
'regex',
|
|
10
|
+
'gt',
|
|
11
|
+
'gte',
|
|
12
|
+
'lt',
|
|
13
|
+
'lte',
|
|
14
|
+
'any'
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
class Group(Node):
|
|
18
|
+
def translate_term_names(self, name_map):
|
|
19
|
+
def translate(dom_obj):
|
|
20
|
+
dom_obj.name = name_map.get(dom_obj.name, dom_obj.name)
|
|
21
|
+
self.each(translate, Term)
|
|
22
|
+
|
|
23
|
+
def get_term_names(self):
|
|
24
|
+
"""
|
|
25
|
+
Returns a flat list of the names of all Terms in the query, in
|
|
26
|
+
the order in which they appear. Filters duplicates.
|
|
27
|
+
"""
|
|
28
|
+
field_names = []
|
|
29
|
+
def collect_field_names(dom_obj):
|
|
30
|
+
if not dom_obj.name in field_names:
|
|
31
|
+
field_names.append(dom_obj.name)
|
|
32
|
+
self.each(collect_field_names, Term)
|
|
33
|
+
return field_names
|
|
34
|
+
|
|
35
|
+
def auto_leave_scope(self):
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
def optimize(self):
|
|
39
|
+
children = [c.optimize() for c in self.children]
|
|
40
|
+
self.children = [c for c in children if c is not None]
|
|
41
|
+
children = []
|
|
42
|
+
for child in self.children:
|
|
43
|
+
if type(child) == type(self):
|
|
44
|
+
for grandchild in child.children:
|
|
45
|
+
children.append(grandchild)
|
|
46
|
+
else:
|
|
47
|
+
children.append(child)
|
|
48
|
+
self.children = children
|
|
49
|
+
if not self.children and not self.is_root:
|
|
50
|
+
return None
|
|
51
|
+
if len(self.children) == 1 and not self.is_root:
|
|
52
|
+
return self.children[0]
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def serialize(self, strategy):
|
|
56
|
+
results = [c.serialize(strategy) for c in self.children]
|
|
57
|
+
if self.is_root:
|
|
58
|
+
return strategy.logical_root_group(self, results)
|
|
59
|
+
return strategy.logical_group(results)
|
|
60
|
+
|
|
61
|
+
class And(Group):
|
|
62
|
+
@classmethod
|
|
63
|
+
def is_logical(self):
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def precedence(self):
|
|
68
|
+
return 2
|
|
69
|
+
|
|
70
|
+
def serialize(self, strategy):
|
|
71
|
+
return strategy.logical_and(c.serialize(strategy)
|
|
72
|
+
for c in self.children)
|
|
73
|
+
|
|
74
|
+
class Or(Group):
|
|
75
|
+
@classmethod
|
|
76
|
+
def is_logical(self):
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def precedence(self):
|
|
81
|
+
return 1
|
|
82
|
+
|
|
83
|
+
def serialize(self, strategy):
|
|
84
|
+
return strategy.logical_or(c.serialize(strategy)
|
|
85
|
+
for c in self.children)
|
|
86
|
+
|
|
87
|
+
class Not(Group):
|
|
88
|
+
@classmethod
|
|
89
|
+
def precedence(self):
|
|
90
|
+
return 3
|
|
91
|
+
|
|
92
|
+
def auto_leave_scope(self):
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
def optimize(self):
|
|
96
|
+
children = [c.optimize() for c in self.children]
|
|
97
|
+
self.children = [c for c in children if c is not None]
|
|
98
|
+
if not self.children and not self.is_root:
|
|
99
|
+
return None
|
|
100
|
+
return self
|
|
101
|
+
|
|
102
|
+
def serialize(self, strategy):
|
|
103
|
+
children = [c.serialize(strategy) for c in self.children]
|
|
104
|
+
return strategy.logical_not(children)
|
|
105
|
+
|
|
106
|
+
class Term(Node):
|
|
107
|
+
def __init__(self, name, operator, data):
|
|
108
|
+
assert operator in operators, "unsupported operator {}".format(operator)
|
|
109
|
+
Node.__init__(self)
|
|
110
|
+
self.name = name
|
|
111
|
+
self.operator = str(operator)
|
|
112
|
+
self.data = str(data)
|
|
113
|
+
|
|
114
|
+
def optimize(self):
|
|
115
|
+
return self
|
|
116
|
+
|
|
117
|
+
def each(self, func, node_type):
|
|
118
|
+
if node_type is None or isinstance(self, node_type):
|
|
119
|
+
func(self)
|
|
120
|
+
|
|
121
|
+
def dump(self, indent=0):
|
|
122
|
+
return [(indent * ' ')
|
|
123
|
+
+ self.__class__.__name__ + ': '
|
|
124
|
+
+ self.name + ' ' + self.operator + ' ' + repr(self.data)]
|
|
125
|
+
|
|
126
|
+
def serialize(self, strategy):
|
|
127
|
+
return strategy.term(self.name, self.operator, self.data)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
class FieldHandler(object):
|
|
4
|
+
"""
|
|
5
|
+
Abstract base type for all field handlers.
|
|
6
|
+
|
|
7
|
+
A field handler is an object that you can use to define custom
|
|
8
|
+
behavior when searching a field of a model.
|
|
9
|
+
|
|
10
|
+
You might want to use a field handler if you are using a custom
|
|
11
|
+
model field, or if your query contains information that
|
|
12
|
+
requires client-side processing before being passed to
|
|
13
|
+
the database.
|
|
14
|
+
"""
|
|
15
|
+
db_type = None
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def handles(cls, model, field):
|
|
19
|
+
raise NotImplemented
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def prepare(cls, value):
|
|
23
|
+
return value
|
|
24
|
+
|
|
25
|
+
class StrFieldHandler(FieldHandler):
|
|
26
|
+
db_type = 'STR'
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def handles(cls, model, field):
|
|
30
|
+
return isinstance(field, (models.CharField, models.TextField))
|
|
31
|
+
|
|
32
|
+
class LowerCaseStrFieldHandler(StrFieldHandler):
|
|
33
|
+
db_type = 'LCSTR'
|
|
34
|
+
|
|
35
|
+
class IPAddressFieldHandler(LowerCaseStrFieldHandler):
|
|
36
|
+
@classmethod
|
|
37
|
+
def handles(cls, model, field):
|
|
38
|
+
return isinstance(field, models.GenericIPAddressField)
|
|
39
|
+
|
|
40
|
+
class BooleanFieldHandler(FieldHandler):
|
|
41
|
+
db_type = 'BOOL'
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def handles(cls, model, field):
|
|
45
|
+
return isinstance(field, models.BooleanField)
|
|
46
|
+
|
|
47
|
+
class IntegerFieldHandler(FieldHandler):
|
|
48
|
+
db_type = 'INT'
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def handles(cls, model, field):
|
|
52
|
+
return isinstance(field, (models.IntegerField, models.AutoField))
|
|
53
|
+
|
|
54
|
+
class DateFieldHandler(FieldHandler):
|
|
55
|
+
db_type = 'DATE'
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def handles(cls, model, field):
|
|
59
|
+
return isinstance(field, models.DateField)
|
|
60
|
+
|
|
61
|
+
class DateTimeFieldHandler(FieldHandler):
|
|
62
|
+
db_type = 'DATETIME'
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def handles(cls, model, field):
|
|
66
|
+
return isinstance(field, models.DateTimeField)
|
|
67
|
+
|
|
68
|
+
type_registry = [
|
|
69
|
+
LowerCaseStrFieldHandler,
|
|
70
|
+
IPAddressFieldHandler,
|
|
71
|
+
BooleanFieldHandler,
|
|
72
|
+
IntegerFieldHandler,
|
|
73
|
+
DateTimeFieldHandler,
|
|
74
|
+
DateFieldHandler,
|
|
75
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .serializers.sql import SQLSerializer
|
|
2
|
+
|
|
3
|
+
def sql_from_dom(cls, dom, mode='SELECT', fullnames=None, extra_model=None):
|
|
4
|
+
if not fullnames:
|
|
5
|
+
fullnames = dom.get_term_names()
|
|
6
|
+
if not fullnames:
|
|
7
|
+
return 'SELECT * FROM (SELECT NULL) tbl WHERE 0', [], [] # Empty set
|
|
8
|
+
primary_cls = cls.get_primary_class_from_fullnames(fullnames)
|
|
9
|
+
serializer = SQLSerializer(primary_cls,
|
|
10
|
+
mode=mode,
|
|
11
|
+
fullnames=fullnames,
|
|
12
|
+
extra_model=extra_model)
|
|
13
|
+
sql, args = dom.serialize(serializer)
|
|
14
|
+
return sql, args, fullnames
|