django-searchkit 1.2__tar.gz → 1.3__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_searchkit-1.2/django_searchkit.egg-info → django_searchkit-1.3}/PKG-INFO +1 -1
- {django_searchkit-1.2 → django_searchkit-1.3/django_searchkit.egg-info}/PKG-INFO +1 -1
- {django_searchkit-1.2 → django_searchkit-1.3}/django_searchkit.egg-info/SOURCES.txt +1 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/__version__.py +1 -1
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/admin.py +15 -1
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/filters.py +10 -2
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/forms/fields.py +5 -4
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/forms/search.py +0 -1
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/forms/searchkit.py +36 -13
- django_searchkit-1.3/searchkit/forms/utils.py +154 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/tests.py +1 -1
- django_searchkit-1.3/searchkit/utils.py +13 -0
- django_searchkit-1.2/searchkit/forms/utils.py +0 -178
- {django_searchkit-1.2 → django_searchkit-1.3}/LICENCE +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/MANIFEST.in +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/README.md +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/django_searchkit.egg-info/dependency_links.txt +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/django_searchkit.egg-info/requires.txt +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/django_searchkit.egg-info/top_level.txt +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/django_searchkit.egg-info/zip-safe +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/admin.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/asgi.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/management/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/management/commands/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/management/commands/createtestdata.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/migrations/0001_initial.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/migrations/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/models.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/settings.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/urls.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/example/example/wsgi.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/apps.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/forms/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/migrations/0001_initial.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/migrations/0002_rename_searchkitsearch_search.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/migrations/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/models.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/templatetags/__init__.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/templatetags/searchkit.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/urls.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/searchkit/views.py +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/setup.cfg +0 -0
- {django_searchkit-1.2 → django_searchkit-1.3}/setup.py +0 -0
@@ -1,15 +1,18 @@
|
|
1
1
|
from django.contrib import admin
|
2
2
|
from django.http import HttpResponseRedirect
|
3
3
|
from django.urls import reverse
|
4
|
+
from django.utils.html import format_html
|
4
5
|
from .models import Search
|
5
6
|
from .forms import SearchForm
|
6
7
|
from .filters import SearchkitFilter
|
8
|
+
from .filters import SearchableModelFilter
|
7
9
|
|
8
10
|
|
9
11
|
@admin.register(Search)
|
10
12
|
class SearchkitSearchAdmin(admin.ModelAdmin):
|
11
13
|
form = SearchForm
|
12
|
-
list_display = ('name', 'contenttype', 'created_date')
|
14
|
+
list_display = ('name', 'contenttype', 'created_date', 'apply_search_view')
|
15
|
+
list_filter = (('contenttype', SearchableModelFilter),)
|
13
16
|
|
14
17
|
def get_url_for_applied_search(self, obj):
|
15
18
|
app_label = obj.contenttype.app_label
|
@@ -28,3 +31,14 @@ class SearchkitSearchAdmin(admin.ModelAdmin):
|
|
28
31
|
return HttpResponseRedirect(self.get_url_for_applied_search(obj))
|
29
32
|
else:
|
30
33
|
return super().response_change(request, obj, *args, **kwargs)
|
34
|
+
|
35
|
+
def apply_search_view(self, obj):
|
36
|
+
"""
|
37
|
+
Returns a link to apply the search.
|
38
|
+
"""
|
39
|
+
return format_html(
|
40
|
+
'<a href="{}" >Apply search "{}"</a>',
|
41
|
+
self.get_url_for_applied_search(obj),
|
42
|
+
obj.name
|
43
|
+
)
|
44
|
+
apply_search_view.short_description = 'Apply Search'
|
@@ -1,9 +1,10 @@
|
|
1
|
-
from django.contrib
|
1
|
+
from django.contrib import admin
|
2
2
|
from django.contrib.contenttypes.models import ContentType
|
3
3
|
from .models import Search
|
4
|
+
from .utils import is_searchable_model
|
4
5
|
|
5
6
|
|
6
|
-
class SearchkitFilter(SimpleListFilter):
|
7
|
+
class SearchkitFilter(admin.SimpleListFilter):
|
7
8
|
title = 'Searchkit Filter'
|
8
9
|
parameter_name = 'search'
|
9
10
|
template = 'searchkit/searchkit_filter.html'
|
@@ -26,3 +27,10 @@ class SearchkitFilter(SimpleListFilter):
|
|
26
27
|
if self.value():
|
27
28
|
search = Search.objects.get(id=int(self.value()))
|
28
29
|
return queryset.filter(**search.as_lookups())
|
30
|
+
|
31
|
+
|
32
|
+
class SearchableModelFilter(admin.filters.RelatedFieldListFilter):
|
33
|
+
def __init__(self, *args, **kwargs):
|
34
|
+
super().__init__(*args, **kwargs)
|
35
|
+
contenttypes = ContentType.objects.order_by('app_label', 'model')
|
36
|
+
self.lookup_choices = [(m.id, m) for m in contenttypes if is_searchable_model(m.model_class())]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from django import forms
|
2
|
+
from django.contrib.admin import widgets
|
2
3
|
from django.utils.translation import gettext_lazy as _
|
3
4
|
|
4
5
|
|
@@ -46,10 +47,10 @@ class IntegerRangeField(BaseRangeField):
|
|
46
47
|
class DateRangeField(BaseRangeField):
|
47
48
|
incomplete_message = _("Enter the first and the last date.")
|
48
49
|
field_type = forms.DateField
|
49
|
-
widget_type =
|
50
|
+
widget_type = widgets.AdminDateWidget
|
50
51
|
|
51
52
|
|
52
|
-
class DateTimeRangeField(
|
53
|
+
class DateTimeRangeField(DateRangeField):
|
53
54
|
incomplete_message = _("Enter the first and the last datetime.")
|
54
|
-
field_type = forms.
|
55
|
-
widget_type =
|
55
|
+
field_type = forms.SplitDateTimeField
|
56
|
+
widget_type = widgets.AdminSplitDateTime
|
@@ -1,19 +1,30 @@
|
|
1
1
|
from django import forms
|
2
|
+
from django.apps import apps
|
3
|
+
from django.contrib.admin import widgets
|
4
|
+
from django.contrib.contenttypes.models import ContentType
|
2
5
|
from django.utils.translation import gettext_lazy as _
|
3
6
|
from django.utils.functional import cached_property
|
4
7
|
from .utils import CssClassMixin, FIELD_PLAN, OPERATOR_DESCRIPTION
|
5
8
|
from .utils import SUPPORTED_FIELDS
|
6
9
|
from .utils import ModelTree
|
7
10
|
from .utils import MediaMixin
|
8
|
-
from .
|
11
|
+
from .fields import DateRangeField
|
12
|
+
from ..utils import is_searchable_model
|
9
13
|
|
10
14
|
|
11
15
|
class SearchkitModelForm(forms.Form):
|
12
16
|
"""
|
13
17
|
Form to select a content type.
|
14
18
|
"""
|
19
|
+
def __init__(self, *args, **kwargs):
|
20
|
+
super().__init__(*args, **kwargs)
|
21
|
+
models = [m for m in apps.get_models() if is_searchable_model(m)]
|
22
|
+
ids = [ContentType.objects.get_for_model(m).id for m in models]
|
23
|
+
queryset = self.fields['searchkit_model'].queryset.filter(pk__in=ids)
|
24
|
+
self.fields['searchkit_model'].queryset = queryset
|
25
|
+
|
15
26
|
searchkit_model = forms.ModelChoiceField(
|
16
|
-
queryset=
|
27
|
+
queryset=ContentType.objects.all().order_by('app_label', 'model'),
|
17
28
|
label=_('Model'),
|
18
29
|
empty_label=_('Select a Model'),
|
19
30
|
widget=forms.Select(attrs={
|
@@ -105,27 +116,19 @@ class BaseSearchkitForm(MediaMixin, CssClassMixin, forms.Form):
|
|
105
116
|
return choices
|
106
117
|
|
107
118
|
def _add_field_name_field(self):
|
108
|
-
initial = self.initial.get('field')
|
109
119
|
choices = self._get_model_field_choices()
|
110
|
-
field = forms.ChoiceField(label=_('Model field'), choices=choices
|
120
|
+
field = forms.ChoiceField(label=_('Model field'), choices=choices)
|
111
121
|
field.widget.attrs.update({"class": self.reload_on_change_css_class})
|
112
122
|
self.fields['field'] = field
|
113
123
|
|
114
124
|
def _add_operator_field(self):
|
115
|
-
initial = self.initial.get('operator')
|
116
125
|
choices = [(o, OPERATOR_DESCRIPTION[o]) for o in self.field_plan.keys()]
|
117
|
-
field = forms.ChoiceField(label=_('Operator'), choices=choices
|
126
|
+
field = forms.ChoiceField(label=_('Operator'), choices=choices)
|
118
127
|
field.widget.attrs.update({"class": self.reload_on_change_css_class})
|
119
128
|
self.fields['operator'] = field
|
120
129
|
|
121
130
|
def _add_value_field(self):
|
122
|
-
|
123
|
-
field_class = self.field_plan[self.operator][0]
|
124
|
-
if getattr(field_class, 'choices', None) and getattr(self.model_field, 'choices', None):
|
125
|
-
field = field_class(choices=self.model_field.choices, initial=initial)
|
126
|
-
else:
|
127
|
-
field = field_class()
|
128
|
-
self.fields['value'] = field
|
131
|
+
self.fields['value'] = self.field_plan[self.operator](self.model_field)
|
129
132
|
|
130
133
|
|
131
134
|
class BaseSearchkitFormSet(CssClassMixin, forms.BaseFormSet):
|
@@ -143,6 +146,26 @@ class BaseSearchkitFormSet(CssClassMixin, forms.BaseFormSet):
|
|
143
146
|
def get_default_prefix(self):
|
144
147
|
return "searchkit"
|
145
148
|
|
149
|
+
@cached_property
|
150
|
+
def uses_date_widget(self):
|
151
|
+
"""
|
152
|
+
Check if the form uses a date widget.
|
153
|
+
"""
|
154
|
+
for form in self.forms:
|
155
|
+
for field in form.fields.values():
|
156
|
+
if isinstance(field.widget, (widgets.AdminDateWidget, widgets.AdminSplitDateTime)):
|
157
|
+
return True
|
158
|
+
elif isinstance(field, DateRangeField):
|
159
|
+
return True
|
160
|
+
return False
|
161
|
+
|
162
|
+
@cached_property
|
163
|
+
def forms(self):
|
164
|
+
if self.model:
|
165
|
+
return super().forms
|
166
|
+
else:
|
167
|
+
return []
|
168
|
+
|
146
169
|
|
147
170
|
def searchkit_formset_factory(model, **kwargs):
|
148
171
|
form = type('SearchkitForm', (BaseSearchkitForm,), dict(model=model))
|
@@ -0,0 +1,154 @@
|
|
1
|
+
from modeltree import ModelTree as BaseModelTree
|
2
|
+
from collections import OrderedDict
|
3
|
+
from django.contrib.admin.widgets import AdminDateWidget, AdminSplitDateTime
|
4
|
+
from django.db import models
|
5
|
+
from django import forms
|
6
|
+
from django.utils.translation import gettext_lazy as _
|
7
|
+
from . import fields as searchkit_fields
|
8
|
+
|
9
|
+
|
10
|
+
class ModelTree(BaseModelTree):
|
11
|
+
MAX_DEPTH = 3
|
12
|
+
FOLLOW_ACROSS_APPS = True
|
13
|
+
RELATION_TYPES = [
|
14
|
+
'one_to_one',
|
15
|
+
'many_to_one',
|
16
|
+
]
|
17
|
+
|
18
|
+
|
19
|
+
OPERATOR_DESCRIPTION = {
|
20
|
+
'exact': _('is exact'),
|
21
|
+
'contains': _('contains'),
|
22
|
+
'startswith': _('starts with'),
|
23
|
+
'endswith': _('ends with'),
|
24
|
+
'regex': _('matches regular expression'),
|
25
|
+
'gt': _('is greater than'),
|
26
|
+
'gte': _('is greater than or equal'),
|
27
|
+
'lt': _('is lower than'),
|
28
|
+
'lte': _('is lower than or equal'),
|
29
|
+
'range': _('is between'),
|
30
|
+
'in': _('is one of'),
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
SUPPORTED_FIELDS = [
|
35
|
+
models.BooleanField,
|
36
|
+
models.CharField,
|
37
|
+
models.IntegerField,
|
38
|
+
models.FloatField,
|
39
|
+
models.DecimalField,
|
40
|
+
models.DateField,
|
41
|
+
models.DateTimeField,
|
42
|
+
]
|
43
|
+
|
44
|
+
|
45
|
+
FIELD_PLAN = OrderedDict((
|
46
|
+
(
|
47
|
+
lambda f: isinstance(f, models.BooleanField),
|
48
|
+
{
|
49
|
+
'exact': lambda f: forms.NullBooleanField() if f.null else forms.BooleanField(),
|
50
|
+
}
|
51
|
+
),
|
52
|
+
(
|
53
|
+
lambda f: isinstance(f, models.CharField) and f.choices,
|
54
|
+
{
|
55
|
+
'exact': lambda f: forms.ChoiceField(choices=f.choices),
|
56
|
+
'contains': lambda f: forms.CharField(),
|
57
|
+
'startswith': lambda f: forms.CharField(),
|
58
|
+
'endswith': lambda f: forms.CharField(),
|
59
|
+
'regex': lambda f: forms.CharField(),
|
60
|
+
'in': lambda f: forms.MultipleChoiceField(choices=f.choices),
|
61
|
+
}
|
62
|
+
),
|
63
|
+
(
|
64
|
+
lambda f: isinstance(f, models.CharField),
|
65
|
+
{
|
66
|
+
'exact': lambda f: forms.CharField(),
|
67
|
+
'contains': lambda f: forms.CharField(),
|
68
|
+
'startswith': lambda f: forms.CharField(),
|
69
|
+
'endswith': lambda f: forms.CharField(),
|
70
|
+
'regex': lambda f: forms.CharField(),
|
71
|
+
}
|
72
|
+
),
|
73
|
+
(
|
74
|
+
lambda f: isinstance(f, models.IntegerField) and f.choices,
|
75
|
+
{
|
76
|
+
'exact': lambda f: forms.ChoiceField(choices=f.choices),
|
77
|
+
'gt': lambda f: forms.IntegerField(),
|
78
|
+
'gte': lambda f: forms.IntegerField(),
|
79
|
+
'lt': lambda f: forms.IntegerField(),
|
80
|
+
'lte': lambda f: forms.IntegerField(),
|
81
|
+
'range': lambda f: searchkit_fields.IntegerRangeField(),
|
82
|
+
'in': lambda f: forms.MultipleChoiceField(choices=f.choices),
|
83
|
+
}
|
84
|
+
),
|
85
|
+
(
|
86
|
+
lambda f: isinstance(f, models.IntegerField),
|
87
|
+
{
|
88
|
+
'exact': lambda f: forms.IntegerField(),
|
89
|
+
'gt': lambda f: forms.IntegerField(),
|
90
|
+
'gte': lambda f: forms.IntegerField(),
|
91
|
+
'lt': lambda f: forms.IntegerField(),
|
92
|
+
'lte': lambda f: forms.IntegerField(),
|
93
|
+
'range': lambda f: searchkit_fields.IntegerRangeField(),
|
94
|
+
}
|
95
|
+
),
|
96
|
+
(
|
97
|
+
lambda f: isinstance(f, models.FloatField),
|
98
|
+
{
|
99
|
+
'exact': lambda f: forms.FloatField(),
|
100
|
+
'gt': lambda f: forms.FloatField(),
|
101
|
+
'gte': lambda f: forms.FloatField(),
|
102
|
+
'lt': lambda f: forms.FloatField(),
|
103
|
+
'lte': lambda f: forms.FloatField(),
|
104
|
+
'range': lambda f: searchkit_fields.IntegerRangeField(),
|
105
|
+
}
|
106
|
+
),
|
107
|
+
(
|
108
|
+
lambda f: isinstance(f, models.DecimalField),
|
109
|
+
{
|
110
|
+
'exact': lambda f: forms.DecimalField(),
|
111
|
+
'gt': lambda f: forms.DecimalField(),
|
112
|
+
'gte': lambda f: forms.DecimalField(),
|
113
|
+
'lt': lambda f: forms.DecimalField(),
|
114
|
+
'lte': lambda f: forms.DecimalField(),
|
115
|
+
'range': lambda f: searchkit_fields.IntegerRangeField(),
|
116
|
+
}
|
117
|
+
),
|
118
|
+
(
|
119
|
+
lambda f: isinstance(f, models.DateTimeField),
|
120
|
+
{
|
121
|
+
'exact': lambda f: forms.SplitDateTimeField(widget=AdminSplitDateTime()),
|
122
|
+
'gt': lambda f: forms.SplitDateTimeField(widget=AdminSplitDateTime()),
|
123
|
+
'gte': lambda f: forms.SplitDateTimeField(widget=AdminSplitDateTime()),
|
124
|
+
'lt': lambda f: forms.SplitDateTimeField(widget=AdminSplitDateTime()),
|
125
|
+
'lte': lambda f: forms.SplitDateTimeField(widget=AdminSplitDateTime()),
|
126
|
+
'range': lambda f: searchkit_fields.DateTimeRangeField(),
|
127
|
+
}
|
128
|
+
),
|
129
|
+
(
|
130
|
+
lambda f: isinstance(f, models.DateField),
|
131
|
+
{
|
132
|
+
'exact': lambda f: forms.DateField(widget=AdminDateWidget()),
|
133
|
+
'gt': lambda f: forms.DateField(widget=AdminDateWidget()),
|
134
|
+
'gte': lambda f: forms.DateField(widget=AdminDateWidget()),
|
135
|
+
'lt': lambda f: forms.DateField(widget=AdminDateWidget()),
|
136
|
+
'lte': lambda f: forms.DateField(widget=AdminDateWidget()),
|
137
|
+
'range': lambda f: searchkit_fields.DateRangeField(),
|
138
|
+
}
|
139
|
+
),
|
140
|
+
))
|
141
|
+
|
142
|
+
|
143
|
+
class CssClassMixin:
|
144
|
+
reload_on_change_css_class = "searchkit-reload-on-change"
|
145
|
+
reload_on_click_css_class = "searchkit-reload-on-click"
|
146
|
+
|
147
|
+
|
148
|
+
class MediaMixin:
|
149
|
+
class Media:
|
150
|
+
js = [
|
151
|
+
'admin/js/vendor/jquery/jquery.min.js',
|
152
|
+
'admin/js/jquery.init.js',
|
153
|
+
"searchkit/searchkit.js"
|
154
|
+
]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from django.contrib import admin
|
2
|
+
|
3
|
+
|
4
|
+
def is_searchable_model(model):
|
5
|
+
"""
|
6
|
+
Check if the model is searchable by Searchkit.
|
7
|
+
"""
|
8
|
+
# We do not import SearchkitFilter to avoid circular imports. So we check
|
9
|
+
# the filter by its name.
|
10
|
+
return (
|
11
|
+
admin.site.is_registered(model)
|
12
|
+
and 'SearchkitFilter' in [getattr(f, '__name__', '') for f in admin.site._registry[model].list_filter]
|
13
|
+
)
|
@@ -1,178 +0,0 @@
|
|
1
|
-
from modeltree import ModelTree as BaseModelTree
|
2
|
-
from collections import OrderedDict
|
3
|
-
from django.apps import apps
|
4
|
-
from django.contrib import admin
|
5
|
-
from django.contrib.contenttypes.models import ContentType
|
6
|
-
from django.db import models
|
7
|
-
from django.db.utils import OperationalError
|
8
|
-
from django import forms
|
9
|
-
from django.utils.translation import gettext_lazy as _
|
10
|
-
from ..filters import SearchkitFilter
|
11
|
-
from . import fields as searchkit_fields
|
12
|
-
|
13
|
-
|
14
|
-
class ModelTree(BaseModelTree):
|
15
|
-
MAX_DEPTH = 3
|
16
|
-
FOLLOW_ACROSS_APPS = True
|
17
|
-
RELATION_TYPES = [
|
18
|
-
'one_to_one',
|
19
|
-
'many_to_one',
|
20
|
-
]
|
21
|
-
|
22
|
-
|
23
|
-
OPERATOR_DESCRIPTION = {
|
24
|
-
'exact': _('is exact'),
|
25
|
-
'contains': _('contains'),
|
26
|
-
'startswith': _('starts with'),
|
27
|
-
'endswith': _('ends with'),
|
28
|
-
'regex': _('matches regular expression'),
|
29
|
-
'gt': _('is greater than'),
|
30
|
-
'gte': _('is greater than or equal'),
|
31
|
-
'lt': _('is lower than'),
|
32
|
-
'lte': _('is lower than or equal'),
|
33
|
-
'range': _('is between'),
|
34
|
-
'in': _('is one of'),
|
35
|
-
}
|
36
|
-
|
37
|
-
|
38
|
-
SUPPORTED_FIELDS = [
|
39
|
-
models.BooleanField,
|
40
|
-
models.CharField,
|
41
|
-
models.IntegerField,
|
42
|
-
models.FloatField,
|
43
|
-
models.DecimalField,
|
44
|
-
models.DateField,
|
45
|
-
models.DateTimeField,
|
46
|
-
]
|
47
|
-
|
48
|
-
|
49
|
-
FIELD_PLAN = OrderedDict((
|
50
|
-
(
|
51
|
-
lambda f: isinstance(f, models.BooleanField),
|
52
|
-
{
|
53
|
-
'exact': (forms.NullBooleanField,),
|
54
|
-
}
|
55
|
-
),
|
56
|
-
(
|
57
|
-
lambda f: isinstance(f, models.CharField) and f.choices,
|
58
|
-
{
|
59
|
-
'exact': (forms.ChoiceField,),
|
60
|
-
'contains': (forms.CharField,),
|
61
|
-
'startswith': (forms.CharField,),
|
62
|
-
'endswith': (forms.CharField,),
|
63
|
-
'regex': (forms.CharField,),
|
64
|
-
'in': (forms.MultipleChoiceField,),
|
65
|
-
}
|
66
|
-
),
|
67
|
-
(
|
68
|
-
lambda f: isinstance(f, models.CharField),
|
69
|
-
{
|
70
|
-
'exact': (forms.CharField,),
|
71
|
-
'contains': (forms.CharField,),
|
72
|
-
'startswith': (forms.CharField,),
|
73
|
-
'endswith': (forms.CharField,),
|
74
|
-
'regex': (forms.CharField,),
|
75
|
-
}
|
76
|
-
),
|
77
|
-
(
|
78
|
-
lambda f: isinstance(f, models.IntegerField) and f.choices,
|
79
|
-
{
|
80
|
-
'exact': (forms.ChoiceField,),
|
81
|
-
'contains': (forms.IntegerField,),
|
82
|
-
'startswith': (forms.IntegerField,),
|
83
|
-
'endswith': (forms.IntegerField,),
|
84
|
-
'regex': (forms.IntegerField,),
|
85
|
-
'in': (forms.MultipleChoiceField,),
|
86
|
-
}
|
87
|
-
),
|
88
|
-
(
|
89
|
-
lambda f: isinstance(f, models.IntegerField),
|
90
|
-
{
|
91
|
-
'exact': (forms.IntegerField,),
|
92
|
-
'gt': (forms.IntegerField,),
|
93
|
-
'gte': (forms.IntegerField,),
|
94
|
-
'lt': (forms.IntegerField,),
|
95
|
-
'lte': (forms.IntegerField,),
|
96
|
-
'range': (searchkit_fields.IntegerRangeField,),
|
97
|
-
}
|
98
|
-
),
|
99
|
-
(
|
100
|
-
lambda f: isinstance(f, models.FloatField),
|
101
|
-
{
|
102
|
-
'exact': (forms.FloatField,),
|
103
|
-
'gt': (forms.FloatField,),
|
104
|
-
'gte': (forms.FloatField,),
|
105
|
-
'lt': (forms.FloatField,),
|
106
|
-
'lte': (forms.FloatField,),
|
107
|
-
'range': (searchkit_fields.IntegerRangeField,),
|
108
|
-
}
|
109
|
-
),
|
110
|
-
(
|
111
|
-
lambda f: isinstance(f, models.DecimalField),
|
112
|
-
{
|
113
|
-
'exact': (forms.DecimalField,),
|
114
|
-
'gt': (forms.DecimalField,),
|
115
|
-
'gte': (forms.DecimalField,),
|
116
|
-
'lt': (forms.DecimalField,),
|
117
|
-
'lte': (forms.DecimalField,),
|
118
|
-
'range': (searchkit_fields.IntegerRangeField,),
|
119
|
-
}
|
120
|
-
),
|
121
|
-
(
|
122
|
-
lambda f: isinstance(f, models.DateTimeField),
|
123
|
-
{
|
124
|
-
'exact': (forms.DateTimeField,),
|
125
|
-
'gt': (forms.DateTimeField,),
|
126
|
-
'gte': (forms.DateTimeField,),
|
127
|
-
'lt': (forms.DateTimeField,),
|
128
|
-
'lte': (forms.DateTimeField,),
|
129
|
-
'range': (searchkit_fields.DateTimeRangeField,),
|
130
|
-
}
|
131
|
-
),
|
132
|
-
(
|
133
|
-
lambda f: isinstance(f, models.DateField),
|
134
|
-
{
|
135
|
-
'exact': (forms.DateField,),
|
136
|
-
'gt': (forms.DateField,),
|
137
|
-
'gte': (forms.DateField,),
|
138
|
-
'lt': (forms.DateField,),
|
139
|
-
'lte': (forms.DateField,),
|
140
|
-
'range': (searchkit_fields.DateRangeField,),
|
141
|
-
}
|
142
|
-
),
|
143
|
-
))
|
144
|
-
|
145
|
-
|
146
|
-
class CssClassMixin:
|
147
|
-
reload_on_change_css_class = "searchkit-reload-on-change"
|
148
|
-
reload_on_click_css_class = "searchkit-reload-on-click"
|
149
|
-
|
150
|
-
|
151
|
-
class MediaMixin:
|
152
|
-
class Media:
|
153
|
-
js = [
|
154
|
-
'admin/js/vendor/jquery/jquery.min.js',
|
155
|
-
'admin/js/jquery.init.js',
|
156
|
-
"searchkit/searchkit.js"
|
157
|
-
]
|
158
|
-
|
159
|
-
|
160
|
-
def is_searchable_model(model):
|
161
|
-
"""
|
162
|
-
Check if the model is searchable by Searchkit.
|
163
|
-
"""
|
164
|
-
return admin.site.is_registered(model) and SearchkitFilter in admin.site._registry[model].list_filter
|
165
|
-
|
166
|
-
|
167
|
-
def get_searchable_models():
|
168
|
-
"""
|
169
|
-
Return a queryset of searchable models.
|
170
|
-
"""
|
171
|
-
# Before mirating the database we get an OperationalError when trying to
|
172
|
-
# access ContentType database table.
|
173
|
-
try:
|
174
|
-
models = [m for m in apps.get_models() if is_searchable_model(m)]
|
175
|
-
ids = [ContentType.objects.get_for_model(m).id for m in models]
|
176
|
-
return ContentType.objects.filter(pk__in=ids).order_by('app_label', 'model')
|
177
|
-
except OperationalError:
|
178
|
-
return ContentType.objects.all()
|
File without changes
|
File without changes
|
File without changes
|
{django_searchkit-1.2 → django_searchkit-1.3}/django_searchkit.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{django_searchkit-1.2 → django_searchkit-1.3}/example/example/management/commands/__init__.py
RENAMED
File without changes
|
{django_searchkit-1.2 → django_searchkit-1.3}/example/example/management/commands/createtestdata.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|