{"library":"django-filter","title":"django-filter","description":"Django-filter is a reusable Django application for allowing users to filter querysets dynamically. It uses a CalVer versioning scheme (Year.ReleaseNumber) and aims to support all current Django versions, matching Python versions, and the latest Django REST Framework.","status":"active","version":"25.2","language":"en","source_language":"en","source_url":"https://github.com/carltongibson/django-filter/tree/main","tags":["django","filter","queryset","drf","rest-framework"],"install":[{"cmd":"pip install django-filter","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core dependency for any django-filter usage.","package":"Django","optional":false},{"reason":"Required for Django REST Framework integration.","package":"djangorestframework","optional":true}],"imports":[{"note":"While 'from django_filters import FilterSet' works, the recommended pattern in documentation for declaring a FilterSet is to import the module as 'django_filters' and refer to FilterSet via 'django_filters.FilterSet'.","wrong":"from django_filters import FilterSet","symbol":"FilterSet","correct":"import django_filters\n\nclass MyFilter(django_filters.FilterSet):"},{"symbol":"CharFilter","correct":"import django_filters\n\nmy_field = django_filters.CharFilter(...)"},{"symbol":"DjangoFilterBackend","correct":"from django_filters.rest_framework import DjangoFilterBackend"}],"quickstart":{"code":"import django_filters\nfrom django.db import models\nfrom django.views.generic import ListView\nfrom rest_framework import generics\nfrom rest_framework import serializers\nfrom django_filters.rest_framework import DjangoFilterBackend\n\n# 1. Define a Django Model\nclass Product(models.Model):\n    name = models.CharField(max_length=255)\n    price = models.DecimalField(max_digits=5, decimal_places=2)\n    release_date = models.DateField(null=True, blank=True)\n    in_stock = models.BooleanField(default=True)\n\n    def __str__(self):\n        return self.name\n\n    class Meta:\n        app_label = 'myapp' # Required for models in standalone snippets\n\n# 2. Define a FilterSet for the Model\nclass ProductFilter(django_filters.FilterSet):\n    name = django_filters.CharFilter(lookup_expr='icontains')\n    price_gt = django_filters.NumberFilter(field_name='price', lookup_expr='gt')\n    price_lt = django_filters.NumberFilter(field_name='price', lookup_expr='lt')\n\n    class Meta:\n        model = Product\n        fields = ['name', 'price', 'release_date', 'in_stock']\n\n# 3. Use with a Django Class-Based View\n# (Requires Django URL configuration and template setup)\nclass ProductListView(ListView):\n    model = Product\n    template_name = 'product_list.html' # Dummy template for example\n    context_object_name = 'products'\n\n    def get_queryset(self):\n        queryset = super().get_queryset()\n        filter = ProductFilter(self.request.GET, queryset=queryset)\n        return filter.qs\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['filter'] = ProductFilter(self.request.GET, queryset=self.get_queryset())\n        return context\n\n# 4. Use with Django REST Framework\nclass ProductSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = Product\n        fields = '__all__'\n\nclass ProductAPIView(generics.ListAPIView):\n    queryset = Product.objects.all()\n    serializer_class = ProductSerializer\n    filter_backends = [DjangoFilterBackend]\n    filterset_class = ProductFilter # Or filterset_fields = ['name', 'price'] for simpler cases\n\n# To run this code, you would need:\n# - A Django project and app ('myapp').\n# - Add 'django_filters' and 'rest_framework' to INSTALLED_APPS in settings.py.\n# - Define URL patterns for ProductListView and ProductAPIView.\n# - Run migrations to create the Product model.\n# - Optionally, create 'product_list.html' template for the ListView.","lang":"python","description":"This quickstart demonstrates defining a `FilterSet` for a Django model and integrating it with a standard Django class-based view (`ListView`) and a Django REST Framework `generics.ListAPIView`. For DRF, `DjangoFilterBackend` is added to `filter_backends` and the `filterset_class` or `filterset_fields` is specified on the view. Remember to add `django_filters` and `rest_framework` to `INSTALLED_APPS` in your Django `settings.py`."},"warnings":[{"fix":"Consult the official migration guide for 2.0 to update your code.","message":"Version 2.0 introduced several breaking changes, including the removal of the list form for `Filter.lookup_expr`, the `filter_for_reverse_field` method, and `FilterSet Meta.together`. View attributes like `filter_class` were renamed to `filterset_class`, and `FilterSet` strictness handling was moved to the view layer.","severity":"breaking","affected_versions":"<2.0.0"},{"fix":"Upgrade to 2.1.0 or later. If on 2.0.0, ensure `strict=False` on affected `FilterSet`s if you observe empty querysets for unbound filters.","message":"A regression in version 2.0 incorrectly caused `FilterView` to use an empty `QuerySet` when the `FilterSet` was unbound (no GET parameters). This was fixed in 2.1.0. A common workaround was setting `strict=False` on the `FilterSet`, which is no longer necessary after the fix.","severity":"gotcha","affected_versions":"2.0.0"},{"fix":"Migrate to `drf-spectacular` for generating OpenAPI schemas with Django REST Framework.","message":"The in-built API schema generation methods of `DjangoFilterBackend` were deprecated in v23.2 and subsequently removed in v25.1.","severity":"breaking","affected_versions":">=25.1"},{"fix":"Regularly update your Python and Django versions to supported releases as per the official `django-filter` and Django EOL policies. Check `django-filter` documentation for current supported versions.","message":"Support for Python and Django versions is dropped when they reach end-of-life. For example, Python 3.8 support was dropped in v25.1.","severity":"breaking","affected_versions":"Varies by EOL policy"},{"fix":"Explicitly define `lookup_expr='icontains'` (or similar) on `CharFilter` and `TextFilter` instances when partial text matching is desired. Example: `name = django_filters.CharFilter(lookup_expr='icontains')`.","message":"For text search filters (`CharField`, `TextField`), it's a common mistake to forget to set `lookup_expr` (e.g., to `icontains` for partial, case-insensitive matches). The default lookup is `exact`, which may lead to unexpected 'no results' for partial searches.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Implement a custom filter method or use 'magic values' in your query parameters to explicitly signal an empty string filter, as described in the official documentation under 'Filtering by empty values'.","message":"Filtering by truly empty string values is not directly supported, as empty values in query parameters are typically interpreted as 'skipped filter'.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Upgrade to 2.4.0 or later. If upgrading is not immediately possible, consider implementing custom validation on `NumberFilter` fields to limit maximum values. The default limit is `1e50` and can be customized via `NumberFilter.get_max_validator()`.","message":"A `MaxValueValidator` was added to the form field for `NumberFilter` in version 2.4.0 to prevent potential DoS attacks from very large exponents being converted to integers.","severity":"security","affected_versions":"<2.4.0"}],"env_vars":null,"last_verified":"2026-04-05T00:00:00.000Z","next_check":"2026-07-04T00:00:00.000Z"}