├── .bumpversion.cfg ├── .flake8 ├── .gitignore ├── .isort.cfg ├── .pylintrc ├── LICENCE ├── MANIFEST.in ├── README.md ├── Rakefile ├── djaa_list_filter ├── __init__.py ├── admin.py ├── apps.py ├── static │ └── djaa_list_filter │ │ └── admin │ │ ├── css │ │ └── autocomplete_list_filter.css │ │ └── js │ │ └── autocomplete_list_filter.js └── templates │ └── djaa_list_filter │ └── admin │ └── filter │ └── autocomplete_list_filter.html ├── pyproject.toml ├── screenshots ├── after.png ├── before.png └── demo.gif ├── setup.py └── tea.yaml /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 1.0.1 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | 8 | [bumpversion:file:djaa_list_filter/__init__.py] 9 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 119 3 | ignore = W503 4 | exclude = 5 | .git, 6 | __pycache__, 7 | docs/source/conf.py, 8 | old, 9 | build, 10 | dist, 11 | migrations 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/python 3 | # Edit at https://www.gitignore.io/?templates=python 4 | 5 | ### Python ### 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | pip-wheel-metadata/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # celery beat schedule file 99 | celerybeat-schedule 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # End of https://www.gitignore.io/api/python 132 | 133 | config/settings/development.py 134 | config/settings/test.py 135 | /media/ 136 | .tm_properties 137 | !.gitkeep -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | line_length = 60 3 | multi_line_output = 3 4 | use_parentheses = true 5 | include_trailing_comma = true 6 | quiet = true 7 | force_grid_wrap = 0 8 | known_django = django 9 | sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER 10 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | /Users/vigo/Repos/Dropbox/Files/configs/pylintrc -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Demirören Teknoloji 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include djaa_list_filter/static * 2 | recursive-include djaa_list_filter/templates * -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Python](https://img.shields.io/badge/python-3.5-green.svg) 2 | ![Python](https://img.shields.io/badge/python-3.6-green.svg) 3 | ![Python](https://img.shields.io/badge/python-3.7-green.svg) 4 | ![Python](https://img.shields.io/badge/python-3.9-green.svg) 5 | ![Django](https://img.shields.io/badge/django-3.+-green.svg) 6 | ![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg) 7 | [![PyPI version](https://badge.fury.io/py/django-admin-autocomplete-list-filter.svg)](https://badge.fury.io/py/django-admin-autocomplete-list-filter) 8 | [![Downloads](https://pepy.tech/badge/django-admin-autocomplete-list-filter)](https://pepy.tech/project/django-admin-autocomplete-list-filter) 9 | 10 | # django-admin-autocomplete-list-filter 11 | 12 | Ajax autocomplete list filter helper for Django admin. Uses Django’s built-in 13 | autocomplete widget! No extra package or install required! 14 | 15 | ![After](screenshots/demo.gif?v=2 "Widget in action...") 16 | 17 | ## Update 18 | 19 | Dropped support for Django 2 family. Works with **Django 3** or higher!. `master` 20 | branch is renamed to `main`... You can fix your existing clones via; 21 | 22 | ```bash 23 | git branch -m master main 24 | git fetch origin 25 | git branch -u origin/main main 26 | git remote set-head origin -a 27 | ``` 28 | 29 | ## Installation and Usage 30 | 31 | ```bash 32 | $ pip install django-admin-autocomplete-list-filter 33 | ``` 34 | 35 | Add `djaa_list_filter` to `INSTALLED_APPS` in your `settings.py`: 36 | 37 | ```python 38 | INSTALLED_APPS = [ 39 | 'django.contrib.admin', 40 | 'django.contrib.auth', 41 | 'django.contrib.contenttypes', 42 | 'django.contrib.sessions', 43 | 'django.contrib.messages', 44 | 'django.contrib.staticfiles', 45 | 'djaa_list_filter', 46 | ] 47 | ``` 48 | 49 | Now, let’s look at this example model: 50 | 51 | ```python 52 | # models.py 53 | 54 | from django.conf import settings 55 | from django.db import models 56 | 57 | 58 | class Post(models.Model): 59 | category = models.ForeignKey(to='Category', on_delete=models.CASCADE, related_name='posts') 60 | author = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='posts') 61 | title = models.CharField(max_length=255) 62 | body = models.TextField() 63 | tags = models.ManyToManyField(to='Tag', blank=True) 64 | 65 | def __str__(self): 66 | return self.title 67 | 68 | 69 | class Category(models.Model): 70 | title = models.CharField(max_length=255) 71 | 72 | def __str__(self): 73 | return self.title 74 | 75 | 76 | class Tag(models.Model): 77 | name = models.CharField(max_length=255) 78 | 79 | def __str__(self): 80 | return self.name 81 | 82 | ``` 83 | 84 | We have 2 **ForeignKey** fields and one **ManyToManyField** to enable 85 | autocomplete list filter feature on admin. All you need is to inherit from 86 | `AjaxAutocompleteListFilterModelAdmin` which inherits from Django’s 87 | `admin.ModelAdmin`. 88 | 89 | Now we have an extra ModelAdmin method: `autocomplete_list_filter`. Uses 90 | Django Admin’s `search_fields` logic. You need to enable `search_fields` 91 | in the related ModelAdmin. To enable completion on `Category` relation, 92 | `CategoryAdmin` should have `search_fields` that’s it! 93 | 94 | ```python 95 | from django.contrib import admin 96 | 97 | from djaa_list_filter.admin import ( 98 | AjaxAutocompleteListFilterModelAdmin, 99 | ) 100 | 101 | from .models import Category, Post, Tag 102 | 103 | 104 | @admin.register(Post) 105 | class PostAdmin(AjaxAutocompleteListFilterModelAdmin): 106 | list_display = ('__str__', 'author', 'show_tags') 107 | autocomplete_list_filter = ('category', 'author', 'tags') 108 | 109 | def show_tags(self, obj): 110 | return ' , '.join(obj.tags.values_list('name', flat=True)) 111 | 112 | 113 | @admin.register(Category) 114 | class CategoryAdmin(admin.ModelAdmin): 115 | search_fields = ['title'] 116 | ordering = ['title'] 117 | 118 | 119 | @admin.register(Tag) 120 | class TagAdmin(admin.ModelAdmin): 121 | search_fields = ['name'] 122 | ordering = ['name'] 123 | 124 | ``` 125 | 126 | ## Development 127 | 128 | You are very welcome to contribute, fix bugs or improve this project. We 129 | hope to help people who needs this feature. We made this package for 130 | our company project. Good appetite for all the Django developers out there! 131 | 132 | ## License 133 | 134 | This project is licensed under MIT 135 | 136 | --- 137 | 138 | ## Contributor(s) 139 | 140 | * [Uğur "vigo" Özyılmazel](https://github.com/vigo) - Author, Maintainer 141 | * [Can Adıyaman](https://github.com/canadiyaman) - Author, Maintainer 142 | * [Erdi Mollahüseyinoğlu](https://github.com/erdimollahuseyin) - Author, Maintainer 143 | * [Guglielmo Celata](https://github.com/guglielmo) - Contributor 144 | * [Joseph Bane](https://github.com/havocbane) - Contributor 145 | * [Ryohei Endo](https://github.com/rendoh) - Contributor 146 | * [Peter Farrell](https://github.com/maestrofjp) - Contributor 147 | * [Márton Salomváry](https://github.com/salomvary) - Contributor 148 | 149 | --- 150 | 151 | ## Contribute 152 | 153 | All PR’s are welcome! 154 | 155 | 1. `fork` (https://github.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/fork) 156 | 1. Create your `branch` (`git checkout -b my-features`) 157 | 1. `commit` yours (`git commit -am 'added killer options'`) 158 | 1. `push` your `branch` (`git push origin my-features`) 159 | 1. Than create a new **Pull Request**! 160 | 161 | --- 162 | 163 | ## TODO 164 | 165 | - Add unit tests 166 | - Improve JavaScript code :) 167 | 168 | ## Change Log 169 | 170 | **2021-08-17** 171 | 172 | - [Fix Django 3 compatibility changes](https://github.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/pull/6) 173 | - [Allow for more than one autocomplete field](https://github.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/pull/5) 174 | - [staticfiles fix](https://github.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/pull/3) 175 | - `master` branch is renamed to `main` 176 | 177 | **2019-10-25** 178 | 179 | - Remove f-string for older Python versions, will change this on 1.0.0 version 180 | 181 | **2019-10-19** 182 | 183 | - Bump version: 0.1.2 184 | - Add Python 3.5 supports, thanks to [Peter Farrel](https://github.com/maestrofjp) 185 | - Add animated gif :) 186 | - Add future warning for f-strings 187 | 188 | **2019-10-11** 189 | 190 | - Add ManyToManyField support 191 | - Initial release 192 | 193 | **2019-10-07** 194 | 195 | - Init repo... 196 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | task :default => [:install] 2 | 3 | desc "Remove/Delete build..." 4 | task :clean do 5 | rm_rf %w(build dist) 6 | rm_rf Dir.glob("*.egg-info") 7 | puts "Build files are removed..." 8 | end 9 | 10 | desc "Install package for local development purpose" 11 | task :install => [:build] do 12 | system "pip install -e ." 13 | end 14 | 15 | desc "Build package" 16 | task :build => [:clean] do 17 | system "python setup.py sdist bdist_wheel" 18 | end 19 | 20 | namespace :upload do 21 | desc "Upload package to main distro (release)" 22 | task :main => [:build] do 23 | puts "Uploading package to MAIN distro..." 24 | system "twine upload --repository pypi dist/*" 25 | end 26 | desc "Upload package to test distro" 27 | task :test => [:build] do 28 | puts "Uploading package to TEST distro..." 29 | system "twine upload --repository testpypi dist/*" 30 | end 31 | end 32 | 33 | AVAILABLE_REVISIONS = ["major", "minor", "patch"] 34 | desc "Bump version" 35 | task :bump, [:revision] do |t, args| 36 | args.with_defaults(revision: "patch") 37 | abort "Please provide valid revision: #{AVAILABLE_REVISIONS.join(',')}" unless AVAILABLE_REVISIONS.include?(args.revision) 38 | system "bumpversion #{args.revision}" 39 | end 40 | -------------------------------------------------------------------------------- /djaa_list_filter/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.0.1' 2 | -------------------------------------------------------------------------------- /djaa_list_filter/admin.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=R0903,R0913,R0201 2 | 3 | import sys 4 | import warnings 5 | 6 | from django import forms 7 | from django.contrib import admin 8 | from django.contrib.admin.widgets import AutocompleteSelect 9 | from django.db.models.fields.related_descriptors import ( 10 | ManyToManyDescriptor, 11 | ReverseManyToOneDescriptor, 12 | ) 13 | from django.utils.translation import gettext_lazy as _ 14 | 15 | CURRENT_PYTHON = sys.version_info[:2] 16 | REQUIRED_PYTHON_FOR_FSTRING = (3, 6) 17 | USE_FSTRING = CURRENT_PYTHON >= REQUIRED_PYTHON_FOR_FSTRING 18 | 19 | 20 | class WillRemoveInVersion10(FutureWarning): 21 | pass 22 | 23 | 24 | class AjaxAutocompleteSelectWidget(AutocompleteSelect): 25 | def __init__(self, *args, **kwargs): 26 | self.qs_target_value = kwargs.pop('qs_target_value') 27 | self.model_admin = kwargs.pop('model_admin') 28 | self.model = kwargs.pop('model') 29 | self.field_name = kwargs.pop('field_name') 30 | kwargs.update(admin_site=self.model_admin.admin_site) 31 | kwargs.update(field=getattr(self.model, self.field_name).field) 32 | super().__init__(*args, **kwargs) 33 | 34 | def render(self, name, value, attrs=None, renderer=None): 35 | rendered = super().render(name, value, attrs, renderer) 36 | 37 | if not USE_FSTRING: 38 | warnings.warn('Will remove str.format, will use f-strings only', WillRemoveInVersion10) 39 | html_string = ( 40 | '
' 41 | '{rendered}' 42 | '
' 43 | ).format(qs_target_value=self.qs_target_value, rendered=rendered) 44 | return html_string 45 | 46 | 47 | class AjaxAutocompleteListFilter(admin.RelatedFieldListFilter): 48 | title = _('list filter') 49 | parameter_name = '%s__%s__exact' 50 | template = 'djaa_list_filter/admin/filter/autocomplete_list_filter.html' 51 | 52 | def __init__(self, field, request, params, model, model_admin, field_path): 53 | super().__init__(field, request, params, model, model_admin, field_path) 54 | 55 | qs_target_value = self.parameter_name % (field.name, model._meta.pk.name) 56 | queryset = self.get_queryset_for_field(model, field.name) 57 | widget = AjaxAutocompleteSelectWidget( 58 | model_admin=model_admin, model=model, field_name=field.name, qs_target_value=qs_target_value 59 | ) 60 | 61 | class AutocompleteForm(forms.Form): 62 | autocomplete_field = forms.ModelChoiceField(queryset=queryset, widget=widget, required=False) 63 | querystring_value = forms.CharField(widget=forms.HiddenInput()) 64 | 65 | autocomplete_field_initial_value = request.GET.get(qs_target_value, None) 66 | initial_values = dict(querystring_value=request.GET.urlencode()) 67 | if autocomplete_field_initial_value: 68 | initial_values.update(autocomplete_field=autocomplete_field_initial_value) 69 | self.autocomplete_form = AutocompleteForm(initial=initial_values, prefix=field.name) 70 | 71 | def get_queryset_for_field(self, model, name): 72 | """ 73 | Thanks to farhan0581 74 | https://github.com/farhan0581/django-admin-autocomplete-filter/blob/master/admin_auto_filters/filters.py 75 | """ 76 | 77 | field_desc = getattr(model, name) 78 | if isinstance(field_desc, ManyToManyDescriptor): 79 | related_model = field_desc.rel.related_model if field_desc.reverse else field_desc.rel.model 80 | elif isinstance(field_desc, ReverseManyToOneDescriptor): 81 | related_model = field_desc.rel.related_model 82 | else: 83 | return field_desc.get_queryset() 84 | return related_model.objects.get_queryset() 85 | 86 | 87 | class AjaxAutocompleteListFilterModelAdmin(admin.ModelAdmin): 88 | def get_list_filter(self, request): 89 | list_filter = list(super().get_list_filter(request)) 90 | autocomplete_list_filter = self.get_autocomplete_list_filter() 91 | if autocomplete_list_filter: 92 | for field in autocomplete_list_filter: 93 | list_filter.insert(0, (field, AjaxAutocompleteListFilter)) 94 | return list_filter 95 | 96 | def get_autocomplete_list_filter(self): 97 | return list(getattr(self, 'autocomplete_list_filter', [])) 98 | 99 | class Media: 100 | js = [ 101 | 'admin/js/vendor/jquery/jquery.js', 102 | 'admin/js/vendor/select2/select2.full.js', 103 | 'admin/js/vendor/select2/i18n/tr.js', 104 | 'admin/js/jquery.init.js', 105 | 'admin/js/autocomplete.js', 106 | 'djaa_list_filter/admin/js/autocomplete_list_filter.js', 107 | ] 108 | css = { 109 | 'screen': [ 110 | 'admin/css/vendor/select2/select2.css', 111 | 'admin/css/autocomplete.css', 112 | 'djaa_list_filter/admin/css/autocomplete_list_filter.css', 113 | ] 114 | } 115 | -------------------------------------------------------------------------------- /djaa_list_filter/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DjaaListFilterConfig(AppConfig): 5 | name = 'djaa_list_filter' 6 | -------------------------------------------------------------------------------- /djaa_list_filter/static/djaa_list_filter/admin/css/autocomplete_list_filter.css: -------------------------------------------------------------------------------- 1 | .ajax-autocomplete-select-widget-wrapper .select2-container--admin-autocomplete { 2 | width: 100% !important; 3 | } 4 | -------------------------------------------------------------------------------- /djaa_list_filter/static/djaa_list_filter/admin/js/autocomplete_list_filter.js: -------------------------------------------------------------------------------- 1 | function handle_querystring_and_redirect(querystring_value, qs_target_value, selection) { 2 | var required_queryset = []; 3 | if (querystring_value.length > 0) { 4 | for(const field_eq_value of querystring_value.split("&")){ 5 | var [field, value] = field_eq_value.split("="); 6 | if (field != qs_target_value){ 7 | required_queryset.push(field_eq_value) 8 | } 9 | } 10 | } 11 | if (selection.length > 0) { 12 | required_queryset.push(qs_target_value + "=" + selection); 13 | } 14 | window.location.href = "?" + required_queryset.join("&"); 15 | } 16 | 17 | django.jQuery(document).ready(function(){ 18 | django.jQuery(".ajax-autocomplete-select-widget-wrapper select").on('select2:unselect', function(e){ 19 | var qs_target_value = django.jQuery(this).parent().data("qs-target-value"); 20 | var querystring_value = django.jQuery(this).closest("form").find('input[name$="querystring_value"]').val(); 21 | handle_querystring_and_redirect(querystring_value, qs_target_value, ""); 22 | }); 23 | 24 | django.jQuery(".ajax-autocomplete-select-widget-wrapper select").on('change', function(e, choice){ 25 | var selection = django.jQuery(e.target).val() || ""; 26 | var qs_target_value = django.jQuery(this).parent().data("qs-target-value"); 27 | var querystring_value = django.jQuery(this).closest("form").find('input[name$="querystring_value"]').val(); 28 | if(selection.length > 0){ 29 | handle_querystring_and_redirect(querystring_value, qs_target_value, selection); 30 | } 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /djaa_list_filter/templates/djaa_list_filter/admin/filter/autocomplete_list_filter.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 |

{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}

3 | 4 |
5 | 8 | {{ spec.autocomplete_form.querystring_value }} 9 |
10 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 119 3 | py36 = true 4 | skip-string-normalization = true 5 | quiet = true 6 | exclude=''' 7 | /( 8 | \.git 9 | | \.hg 10 | | \.tox 11 | | \.venv 12 | | _build 13 | | buck-out 14 | | build 15 | | dist 16 | )/ 17 | ''' 18 | -------------------------------------------------------------------------------- /screenshots/after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/09e54053415e87246ac13c7293b3100d04c1eee8/screenshots/after.png -------------------------------------------------------------------------------- /screenshots/before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/09e54053415e87246ac13c7293b3100d04c1eee8/screenshots/before.png -------------------------------------------------------------------------------- /screenshots/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/demiroren-teknoloji/django-admin-autocomplete-list-filter/09e54053415e87246ac13c7293b3100d04c1eee8/screenshots/demo.gif -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from setuptools import find_packages, setup 4 | 5 | CURRENT_WORKING_DIRECTORY = os.path.abspath(os.path.dirname(__file__)) 6 | 7 | with open(os.path.join(CURRENT_WORKING_DIRECTORY, 'README.md')) as fp: 8 | README = fp.read() 9 | 10 | setup( 11 | name='django-admin-autocomplete-list-filter', 12 | version='1.0.1', 13 | description='Ajax autocomplete list filter for Django admin', 14 | long_description=README, 15 | long_description_content_type='text/markdown', 16 | url='https://github.com/demiroren-teknoloji/django-admin-autocomplete-list-filter', 17 | author='Demirören Teknoloji Django Team', 18 | author_email='account@demirorenteknoloji.com', 19 | license='MIT', 20 | python_requires='>=3.0', 21 | packages=find_packages(), 22 | classifiers=[ 23 | 'Development Status :: 4 - Beta', 24 | 'Environment :: Web Environment', 25 | 'Framework :: Django', 26 | 'Framework :: Django :: 2.2', 27 | 'Intended Audience :: Developers', 28 | 'License :: OSI Approved :: MIT License', 29 | 'Operating System :: OS Independent', 30 | 'Programming Language :: Python :: 3', 31 | 'Programming Language :: Python :: 3.7', 32 | 'Programming Language :: Python :: 3 :: Only', 33 | 'Topic :: Internet :: WWW/HTTP', 34 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 35 | ], 36 | include_package_data=True, 37 | ) 38 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0xAe01f6b6a72D3a0427A51D38c28b48991AAd3388' 6 | quorum: 1 7 | --------------------------------------------------------------------------------