Metadata-Version: 2.4
Name: django-admin-autocomplete-filters
Version: 0.8.0rc2
Summary: Render admin list filters with Django's autocomplete widget
Author: Farhan Khan
Author-email: Filipp Balakin <filipp@balakin.ru>
Maintainer-email: Filipp Balakin <filipp@balakin.ru>
License-Expression: LGPL-3.0-or-later
Project-URL: Homepage, https://github.com/Barsoomx/django-admin-autocomplete-filters
Project-URL: Repository, https://github.com/Barsoomx/django-admin-autocomplete-filters
Project-URL: Changelog, https://github.com/Barsoomx/django-admin-autocomplete-filters/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/Barsoomx/django-admin-autocomplete-filters/issues
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django<6,>=4.2
Provides-Extra: dev
Requires-Dist: ruff==0.11.7; extra == "dev"
Requires-Dist: django-stubs>=5.0.0; extra == "dev"
Requires-Dist: django-stubs-ext>=5.0.0; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"
Dynamic: license-file

[![PyPI version](https://badge.fury.io/py/django-admin-autocomplete-filters.svg)](https://badge.fury.io/py/django-admin-autocomplete-filters)
[![Tests](https://github.com/Barsoomx/django-admin-autocomplete-filters/actions/workflows/tests.yml/badge.svg)](https://github.com/Barsoomx/django-admin-autocomplete-filters/actions/workflows/tests.yml)
[![Ruff](https://img.shields.io/badge/lint-ruff-46a2f1.svg)](https://github.com/astral-sh/ruff)


Django Admin Autocomplete Filters
=================================
Maintained continuation of the original project by Farhan Khan: https://github.com/farhan0581/django-admin-autocomplete-filter
This fork modernizes packaging (PEP 621), adds CI, and supports Django 4.2–5.2 and Python 3.10+.
A simple Django app to render list filters in django admin using an autocomplete widget. This app is heavily inspired by [dal-admin-filters.](https://github.com/shamanu4/dal_admin_filters)


Overview:
---------

Django comes preshipped with an admin panel which is a great utility to create quick CRUD's.
Version 2.0 came with a much needed [`autocomplete_fields`](https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields "autocomplete_fields") property which uses a select2 widget to load the options asynchronously.  We leverage this in `django-admin-list-filter`.



Requirements:
-------------

- Django >= 4.2
- Python >= 3.10

Supported Versions
------------------
- Python: 3.10, 3.11, 3.12
- Django: 4.2, 5.0, 5.1, 5.2

See the CI badge for the full matrix.


Features:
-------------

* Custom search view/endpoint ([more details](#functionality-to-provide-custom-view-for-search))
* `list_filter` Filter Factory support ([more details](#shortcut-for-creating-filters))
* Custom widget text ([more details](#customizing-widget-text))
* Support for [Grappelli](https://grappelliproject.com/)


Installation:
-------------

You can install it via pip.  To get the latest version clone this repo.

```shell
pip install django-admin-autocomplete-filters
```

Add `admin_auto_filters` to your `INSTALLED_APPS` inside settings.py of your project.


Usage:
------

Let's say we have following models:
```python
from django.db import models

class Artist(models.Model):
    name = models.CharField(max_length=128)

class Album(models.Model):
    name = models.CharField(max_length=64)
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    cover = models.CharField(max_length=256, null=True, default=None)
```

And you would like to filter results in `AlbumAdmin` on the basis of `artist`.  You need to define `search fields` in `Artist` and then define filter like this:

```python
from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilter


class ArtistFilter(AutocompleteFilter):
    title = 'Artist' # display title
    field_name = 'artist' # name of the foreign key field


class ArtistAdmin(admin.ModelAdmin):
    search_fields = ['name'] # this is required for django's autocomplete functionality
    # ...


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [ArtistFilter]
    # ...
```

After following these steps you may see the filter as:

![](admin_auto_filters/media/screenshot1.png)

![](admin_auto_filters/media/screenshot2.png)

Release Process
---------------
- Bump `admin_auto_filters.__version__` and update `CHANGELOG.md`.
- Ensure CI is green on `main`.
- Create a tag `vX.Y.Z` and push; the GitHub Actions workflow will build and publish to PyPI via trusted publishing.

Contributing
------------
See `CONTRIBUTING.md` for local setup, linting, typing, tests, and pre-commit hooks.


Functionality to provide a custom view for search:
--------------------------------------------------

You can also register your custom view instead of using Django admin's `search_results` to control the results in the autocomplete. For this you will need to create your custom view and register the URL in your admin class as shown below:

In your `views.py`:

```python
from admin_auto_filters.views import AutocompleteJsonView


class CustomSearchView(AutocompleteJsonView):
    def get_queryset(self):
        """
           your custom logic goes here.
        """
        queryset = super().get_queryset()
        queryset = queryset.order_by('name')
        return queryset
```

After this, register this view in your admin class:

```python
from django.contrib import admin
from django.urls import path


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [ArtistFilter]

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('custom_search/', self.admin_site.admin_view(CustomSearchView.as_view(model_admin=self)),
                 name='custom_search'),
        ]
        return custom_urls + urls
```

Finally, just tell the filter class to use this new view:

```python
from django.shortcuts import reverse
from admin_auto_filters.filters import AutocompleteFilter


class ArtistFilter(AutocompleteFilter):
    title = 'Artist'
    field_name = 'artist'

    def get_autocomplete_url(self, request, model_admin):
        return reverse('admin:custom_search')
```


Shortcut for creating filters:
------------------------------

It's also possible to use the `AutocompleteFilterFactory` shortcut to create
filters on the fly, as shown below. Nested relations are supported too, with
no need to specify the model.

```python
from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilterFactory


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [
        AutocompleteFilterFactory('Artist', 'artist', 'admin:custom_search', True)
    ]

    def get_urls(self):
        """As above..."""
```


Customizing widget text
-----------------------

You can customize the text displayed in the filter widget, to use something
other than `str(obj)`. This needs to be configured for both the dropdown
endpoint and the widget itself.

In your `views.py`, override `display_text`:

```python
from admin_auto_filters.views import AutocompleteJsonView


class CustomSearchView(AutocompleteJsonView):

    @staticmethod
    def display_text(obj):
        return obj.my_str_method()

    def get_queryset(self):
        """As above..."""
```

Then use either of two options to customize the text.

Option one is to specify the form_field in an AutocompleteFilter in your
`admin.py`:

```python
from django import forms
from django.contrib import admin
from django.shortcuts import reverse
from admin_auto_filters.filters import AutocompleteFilter


class FoodChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.my_str_method()


class ArtistFilter(AutocompleteFilter):
    title = 'Artist'
    field_name = 'artist'
    form_field = FoodChoiceField

    def get_autocomplete_url(self, request, model_admin):
        return reverse('admin:custom_search')


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [ArtistFilter]

    def get_urls(self):
        """As above..."""
```

Option two is to use an AutocompleteFilterFactory in your `admin.py`
add a `label_by` argument:

```python
from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilterFactory


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [
        AutocompleteFilterFactory('Artist', 'artist', 'admin:custom_search', True, label_by='my_str_method')
    ]

    def get_urls(self):
        """As above..."""
```


Contributing:
------------

This project is a combined effort of a lot of selfless developers who try to make things easier. Your contribution is most welcome.

Please make a pull-request to the branch `pre_release`, make sure your branch does not have any conflicts, and clearly mention the problems or improvements your PR is addressing.


License:
--------

Django Admin Autocomplete Filter is an Open Source project licensed under the terms of the GNU GENERAL PUBLIC LICENSE.
