POC works
parent
ca26ca3620
commit
4ca3435f3d
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
# Created by https://www.gitignore.io/api/python
|
||||
# Edit at https://www.gitignore.io/?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# End of https://www.gitignore.io/api/python
|
||||
|
||||
config/settings/development.py
|
||||
config/settings/test.py
|
||||
/media/
|
||||
.tm_properties
|
||||
!.gitkeep
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
# pylint: disable=R0903,R0913
|
||||
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin.widgets import AutocompleteSelect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
||||
class AjaxAutocompleteSelectWidget(AutocompleteSelect):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.qs_target_value = kwargs.pop('qs_target_value')
|
||||
self.model_admin = kwargs.pop('model_admin')
|
||||
self.model = kwargs.pop('model')
|
||||
self.field_name = kwargs.pop('field_name')
|
||||
kwargs['admin_site'] = self.model_admin.admin_site
|
||||
kwargs['rel'] = getattr(self.model, self.field_name).field.remote_field
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def render(self, name, value, attrs=None, renderer=None):
|
||||
rendered = super().render(name, value, attrs, renderer)
|
||||
return (
|
||||
f'<div class="ajax-autocomplete-select-widget-wrapper" data-qs-target-value="{self.qs_target_value}">'
|
||||
f'{rendered}'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
|
||||
class AjaxAutocompleteListFilter(admin.RelatedFieldListFilter):
|
||||
title = _('list filter')
|
||||
parameter_name = '%s__%s__exact'
|
||||
template = 'djaa_list_filter/admin/filter/autocomplete_list_filter.html'
|
||||
|
||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
||||
super().__init__(field, request, params, model, model_admin, field_path)
|
||||
|
||||
qs_target_value = self.parameter_name % (field.name, model._meta.pk.name)
|
||||
queryset = getattr(model, field.name).get_queryset()
|
||||
widget = AjaxAutocompleteSelectWidget(
|
||||
model_admin=model_admin, model=model, field_name=field.name, qs_target_value=qs_target_value
|
||||
)
|
||||
|
||||
class AutocompleteForm(forms.Form):
|
||||
autocomplete_field = forms.ModelChoiceField(queryset=queryset, widget=widget, required=False)
|
||||
querystring_value = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
autocomplete_field_initial_value = request.GET.get(qs_target_value, None)
|
||||
initial_values = dict(querystring_value=request.GET.urlencode())
|
||||
if autocomplete_field_initial_value:
|
||||
initial_values.update(autocomplete_field=autocomplete_field_initial_value)
|
||||
self.autocomplete_form = AutocompleteForm(initial=initial_values)
|
||||
|
||||
|
||||
class AjaxAutocompleteListFilterModelAdmin(admin.ModelAdmin):
|
||||
def get_list_filter(self, request):
|
||||
list_filter = list(super().get_list_filter(request))
|
||||
autocomplete_list_filter = self.get_autocomplete_list_filter()
|
||||
if autocomplete_list_filter:
|
||||
for field in autocomplete_list_filter:
|
||||
list_filter.append((field, AjaxAutocompleteListFilter))
|
||||
return list_filter
|
||||
|
||||
def get_autocomplete_list_filter(self):
|
||||
return list(getattr(self, 'autocomplete_list_filter', []))
|
||||
|
||||
class Media:
|
||||
js = [
|
||||
'admin/js/vendor/jquery/jquery.js',
|
||||
'admin/js/vendor/select2/select2.full.js',
|
||||
'admin/js/vendor/select2/i18n/tr.js',
|
||||
'admin/js/jquery.init.js',
|
||||
'admin/js/autocomplete.js',
|
||||
'djaa_list_filter/admin/js/autocomplete_list_filter.js',
|
||||
]
|
||||
css = {
|
||||
'screen': [
|
||||
'admin/css/vendor/select2/select2.css',
|
||||
'admin/css/autocomplete.css',
|
||||
'djaa_list_filter/admin/css/autocomplete_list_filter.css',
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class DjaaListFilterConfig(AppConfig):
|
||||
name = 'djaa_list_filter'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
.select2-container--admin-autocomplete {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
function handle_querystring_and_redirect(querystring_value, qs_target_value, selection) {
|
||||
var required_queryset = [];
|
||||
for(const field_eq_value of querystring_value.split("&")){
|
||||
var [field, value] = field_eq_value.split("=");
|
||||
if (field != qs_target_value){
|
||||
required_queryset.push(field_eq_value)
|
||||
}
|
||||
}
|
||||
if (selection.length > 0) {
|
||||
required_queryset.push(qs_target_value + "=" + selection);
|
||||
}
|
||||
window.location.href = "?" + required_queryset.join("&");
|
||||
}
|
||||
|
||||
django.jQuery(document).ready(function(){
|
||||
django.jQuery(".ajax-autocomplete-select-widget-wrapper select").on('select2:unselect', function(e){
|
||||
var qs_target_value = django.jQuery(this).parent().data("qs-target-value");
|
||||
var querystring_value = django.jQuery(this).closest("form").find('input[name="querystring_value"]').val();
|
||||
handle_querystring_and_redirect(querystring_value, qs_target_value, "");
|
||||
});
|
||||
|
||||
django.jQuery(".ajax-autocomplete-select-widget-wrapper select").on('change', function(e, choice){
|
||||
var selection = django.jQuery(e.target).val() || "";
|
||||
var qs_target_value = django.jQuery(this).parent().data("qs-target-value");
|
||||
var querystring_value = django.jQuery(this).closest("form").find('input[name="querystring_value"]').val();
|
||||
if(selection.length > 0){
|
||||
handle_querystring_and_redirect(querystring_value, qs_target_value, selection);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{% load i18n staticfiles %}
|
||||
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
|
||||
|
||||
<form method="get">
|
||||
<ul>
|
||||
<li>{{ spec.autocomplete_form.autocomplete_field }}</li>
|
||||
</ul>
|
||||
{{ spec.autocomplete_form.querystring_value }}
|
||||
</form>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 197 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
4
setup.py
4
setup.py
|
|
@ -14,8 +14,8 @@ setup(
|
|||
long_description=README,
|
||||
long_description_content_type='text/markdown',
|
||||
url='https://github.com/demiroren-teknoloji/django-admin-autocomplete-list-filter',
|
||||
author='Uğur Özyılmazel',
|
||||
author_email='ugur.ozyilmazel@demirorenteknoloji.com',
|
||||
author='Uğur Özyılmazel, Can Adıyaman',
|
||||
author_email='ugur.ozyilmazel@demirorenteknoloji.com, can.adiyaman@demirorenteknoloji.com',
|
||||
license='MIT',
|
||||
python_requires='>=3.0',
|
||||
packages=find_packages(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue