POC works

master
Uğur Özyılmazel 2019-10-10 17:16:21 +03:00
parent ca26ca3620
commit 4ca3435f3d
No known key found for this signature in database
GPG Key ID: 43CAF9E2A63DF017
9 changed files with 268 additions and 2 deletions

137
.gitignore vendored 100644
View File

@ -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

View File

@ -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',
]
}

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class DjaaListFilterConfig(AppConfig):
name = 'djaa_list_filter'

View File

@ -0,0 +1,3 @@
.select2-container--admin-autocomplete {
width: 100% !important;
}

View File

@ -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);
}
});
});

View File

@ -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

View File

@ -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(),