[django-filter] Add type stubs (#14540)

This commit is contained in:
Huy Nguyen
2025-08-08 16:34:39 +07:00
committed by GitHub
parent 81c8fcb2e6
commit 2bb3b53b60
18 changed files with 773 additions and 0 deletions
@@ -0,0 +1,12 @@
SECRET_KEY = "1"
INSTALLED_APPS = (
"django.contrib.contenttypes",
"django.contrib.sites",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.admin.apps.SimpleAdminConfig",
"django.contrib.staticfiles",
"django.contrib.auth",
"django_filters",
)
@@ -0,0 +1,12 @@
# Iterator class attributes: Runtime behavior differs due to Django 5.0 compatibility logic in choice setters
django_filters.fields.ChoiceField.iterator
django_filters.fields.ModelChoiceField.iterator
django_filters.fields.ModelMultipleChoiceField.iterator
django_filters.fields.MultipleChoiceField.iterator
# Lookup NamedTuple: Parameter name mismatch between inferred stub and runtime
django_filters.fields.Lookup.__new__
django_filters.fields.Lookup.__doc__
# ChoiceIteratorMixin.choices: Cannot define choices property due to incompatibility with base class ChoiceField
django_filters.fields.ChoiceIteratorMixin.choices
+7
View File
@@ -0,0 +1,7 @@
version = "25.1.*"
upstream_repository = "https://github.com/carltongibson/django-filter/"
requires = ["django-stubs"]
[tool.stubtest]
mypy_plugins = ["mypy_django_plugin.main"]
mypy_plugins_config = {"django-stubs" = {"django_settings_module" = "@tests.django_settings"}}
@@ -0,0 +1,10 @@
from typing import Final
from .filters import *
from .filterset import FilterSet as FilterSet, UnknownFieldBehavior as UnknownFieldBehavior
__version__: Final[str]
def parse_version(version: str) -> tuple[str | int]: ...
VERSION: tuple[str | int, ...]
@@ -0,0 +1 @@
def is_crispy() -> bool: ...
@@ -0,0 +1,17 @@
from _typeshed import Unused
from typing import Any
DEFAULTS: dict[str, Any] # Configuration values can be strings, booleans, callables, etc.
DEPRECATED_SETTINGS: list[str]
def is_callable(value: Any) -> bool: ... # Accepts any value to test if it's callable
class Settings:
# Setting values can be of any type, so getter and setter methods return/accept Any
def __getattr__(self, name: str) -> Any: ... # Returns setting values of various types
def get_setting(self, setting: str) -> Any: ... # Setting values vary by configuration option
def change_setting(
self, setting: str, value: Any, enter: bool, **kwargs: Unused
) -> None: ... # Accepts any setting value type
settings: Settings
@@ -0,0 +1,6 @@
from typing import Any, Final
# String constant used to indicate all model fields should be included
ALL_FIELDS: Final[str] = "__all__"
# Collection of values considered empty by Django filters - tuple type allows various empty containers
EMPTY_VALUES: Final[Any] = ...
@@ -0,0 +1,8 @@
from typing import Any
from django.core.exceptions import FieldError
from django.db import models
class FieldLookupError(FieldError):
# Field type params are runtime-determined
def __init__(self, model_field: models.Field[Any, Any], lookup_expr: str) -> None: ...
@@ -0,0 +1,100 @@
from collections.abc import Sequence
from typing import Any, NamedTuple
from typing_extensions import TypeAlias
from django import forms
DJANGO_50: bool
# Ref: django-stubs/forms/fields.pyi
# Problem: attribute `widget` is always of type `Widget` after field instantiation.
# However, on class level it can be set to `Type[Widget]` too.
# If we annotate it as `Union[Widget, Type[Widget]]`, every code that uses field
# instances will not typecheck.
# If we annotate it as `Widget`, any widget subclasses that do e.g.
# `widget = Select` will not typecheck.
# `Any` gives too much freedom, but does not create false positives.
_ClassLevelWidget: TypeAlias = Any
class RangeField(forms.MultiValueField):
widget: _ClassLevelWidget = ...
def __init__(
self, fields: tuple[forms.Field, forms.Field] | None = None, *args: Any, **kwargs: Any
) -> None: ... # Args/kwargs can be any field params, passes to parent
def compress(self, data_list: list[Any] | None) -> slice | None: ... # Data list elements can be any field value type
class DateRangeField(RangeField):
widget: _ClassLevelWidget = ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent
def compress(self, data_list: list[Any] | None) -> slice | None: ... # Date values in list can be any date type
class DateTimeRangeField(RangeField):
widget: _ClassLevelWidget = ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent
class IsoDateTimeRangeField(RangeField):
widget: _ClassLevelWidget = ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent
class TimeRangeField(RangeField):
widget: _ClassLevelWidget = ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent
class Lookup(NamedTuple):
value: Any # Lookup values can be any filterable type
lookup_expr: str
class LookupChoiceField(forms.MultiValueField):
def __init__(
self, field: forms.Field, lookup_choices: Sequence[tuple[str, str]], *args: Any, **kwargs: Any
) -> None: ... # Args/kwargs can be any field params, uses kwargs for empty_label
def compress(self, data_list: list[Any] | None) -> Lookup | None: ... # Data list can contain any lookup components
class IsoDateTimeField(forms.DateTimeField):
ISO_8601: str
input_formats: list[str]
def strptime(self, value: str, format: str) -> Any: ... # Returns datetime objects or parsing results
class BaseCSVField(forms.Field):
base_widget_class: _ClassLevelWidget = ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for widget config
def clean(self, value: Any) -> Any: ... # Cleaned values can be any valid field type
class BaseRangeField(BaseCSVField):
widget: _ClassLevelWidget = ...
def clean(self, value: Any) -> Any: ... # Input and output values can be any range type
class ChoiceIterator:
field: ChoiceField
choices: Sequence[tuple[Any, str]] # Choice values can be any type (int, str, Model, etc.)
def __init__(
self, field: ChoiceField, choices: Sequence[tuple[Any, str]]
) -> None: ... # Choice values can be any selectable type
def __iter__(self) -> Any: ... # Iterator yields choice tuples with any value types
def __len__(self) -> int: ...
class ModelChoiceIterator(forms.models.ModelChoiceIterator):
def __iter__(self) -> Any: ... # Iterator yields choice tuples with any value types
def __len__(self) -> int: ...
class ChoiceIteratorMixin:
null_label: str | None
null_value: Any # Null choice values can be any type (None, empty string, etc.)
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for null config
class ChoiceField(ChoiceIteratorMixin, forms.ChoiceField):
iterator = ChoiceIterator
empty_label: str | None
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for label config
class MultipleChoiceField(ChoiceIteratorMixin, forms.MultipleChoiceField):
iterator = ChoiceIterator
empty_label: str | None
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params, sets empty_label
class ModelChoiceField(ChoiceIteratorMixin, forms.ModelChoiceField[Any]):
iterator = ModelChoiceIterator
def to_python(self, value: Any) -> Any: ... # Converts any input to Python model objects or values
class ModelMultipleChoiceField(ChoiceIteratorMixin, forms.ModelMultipleChoiceField[Any]):
iterator = ModelChoiceIterator
@@ -0,0 +1,234 @@
from collections.abc import Callable
from typing import Any
from django import forms
from django.db.models import Q, QuerySet
from django.forms import Field
from .fields import (
BaseCSVField,
BaseRangeField,
DateRangeField,
DateTimeRangeField,
IsoDateTimeField,
IsoDateTimeRangeField,
LookupChoiceField,
ModelChoiceField,
ModelMultipleChoiceField,
RangeField,
TimeRangeField,
)
__all__ = [
"AllValuesFilter",
"AllValuesMultipleFilter",
"BaseCSVFilter",
"BaseInFilter",
"BaseRangeFilter",
"BooleanFilter",
"CharFilter",
"ChoiceFilter",
"DateFilter",
"DateFromToRangeFilter",
"DateRangeFilter",
"DateTimeFilter",
"DateTimeFromToRangeFilter",
"DurationFilter",
"Filter",
"IsoDateTimeFilter",
"IsoDateTimeFromToRangeFilter",
"LookupChoiceFilter",
"ModelChoiceFilter",
"ModelMultipleChoiceFilter",
"MultipleChoiceFilter",
"NumberFilter",
"NumericRangeFilter",
"OrderingFilter",
"RangeFilter",
"TimeFilter",
"TimeRangeFilter",
"TypedChoiceFilter",
"TypedMultipleChoiceFilter",
"UUIDFilter",
]
class Filter:
creation_counter: int
field_class: type[Any] # Subclasses specify more specific field types
field_name: str | None
lookup_expr: str
distinct: bool
exclude: bool
extra: dict[str, Any] # Field kwargs can include various types of parameters
def __init__(
self,
field_name: str | None = None,
lookup_expr: str | None = None,
*,
label: str | None = None,
method: Callable[..., Any] | str | None = None, # Filter methods can return various types
distinct: bool = False,
exclude: bool = False,
**kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.)
) -> None: ...
def get_method(self, qs: QuerySet[Any]) -> Callable[..., QuerySet[Any]]: ... # Returns QuerySet filtering methods
method: Callable[..., Any] | str | None # Custom filter methods return various types
label: str | None # Filter label for display
@property
def field(self) -> Field: ...
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ... # Filter value can be any user input type
class CharFilter(Filter):
field_class: type[forms.CharField]
class BooleanFilter(Filter):
field_class: type[forms.NullBooleanField]
class ChoiceFilter(Filter):
field_class: type[Any] # Base class for choice-based filters
null_value: Any # Null value can be any type (None, empty string, etc.)
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for null_value config
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
class TypedChoiceFilter(Filter):
field_class: type[forms.TypedChoiceField]
class UUIDFilter(Filter):
field_class: type[forms.UUIDField]
class MultipleChoiceFilter(Filter):
field_class: type[Any] # Base class for multiple choice filters
always_filter: bool
conjoined: bool
null_value: Any # Multiple choice null values vary by implementation
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for distinct, conjoined, null_value config
def is_noop(self, qs: QuerySet[Any], value: Any) -> bool: ... # Value can be any filter input
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
def get_filter_predicate(self, v: Any) -> Q: ... # Predicate value can be any filter input type
class TypedMultipleChoiceFilter(MultipleChoiceFilter):
field_class: type[forms.TypedMultipleChoiceField] # More specific than parent MultipleChoiceField
class DateFilter(Filter):
field_class: type[forms.DateField]
class DateTimeFilter(Filter):
field_class: type[forms.DateTimeField]
class IsoDateTimeFilter(DateTimeFilter):
field_class: type[IsoDateTimeField]
class TimeFilter(Filter):
field_class: type[forms.TimeField]
class DurationFilter(Filter):
field_class: type[forms.DurationField]
class QuerySetRequestMixin:
queryset: QuerySet[Any] | None
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for queryset config
def get_request(self) -> Any: ... # Request can be HttpRequest or other request types
def get_queryset(self, request: Any) -> QuerySet[Any]: ... # Request parameter accepts various request types
@property
def field(self) -> Field: ...
class ModelChoiceFilter(QuerySetRequestMixin, ChoiceFilter):
field_class: type[ModelChoiceField] # More specific than parent ChoiceField
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for empty_label config
class ModelMultipleChoiceFilter(QuerySetRequestMixin, MultipleChoiceFilter):
field_class: type[ModelMultipleChoiceField] # More specific than parent MultipleChoiceField
class NumberFilter(Filter):
field_class: type[forms.DecimalField]
def get_max_validator(self) -> Any: ... # Validator can be various Django validator types
@property
def field(self) -> Field: ...
class NumericRangeFilter(Filter):
field_class: type[RangeField]
lookup_expr: str
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
class RangeFilter(Filter):
field_class: type[RangeField]
lookup_expr: str
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
class DateRangeFilter(ChoiceFilter):
choices: list[tuple[str, str]] | None
filters: dict[str, Filter] | None
def __init__(
self, choices: list[tuple[str, str]] | None = None, filters: dict[str, Filter] | None = None, *args: Any, **kwargs: Any
) -> None: ... # Uses args/kwargs for choice and filter configuration
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
class DateFromToRangeFilter(RangeFilter):
field_class: type[DateRangeField]
class DateTimeFromToRangeFilter(RangeFilter):
field_class: type[DateTimeRangeField]
class IsoDateTimeFromToRangeFilter(RangeFilter):
field_class: type[IsoDateTimeRangeField]
class TimeRangeFilter(RangeFilter):
field_class: type[TimeRangeField]
class AllValuesFilter(ChoiceFilter):
@property
def field(self) -> Field: ...
class AllValuesMultipleFilter(MultipleChoiceFilter):
@property
def field(self) -> Field: ...
class BaseCSVFilter(Filter):
base_field_class: type[BaseCSVField] = ...
field_class: type[Any] # Base class for CSV-based filters
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for help_text and widget config
class BaseInFilter(BaseCSVFilter):
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Sets lookup_expr and passes through
class BaseRangeFilter(BaseCSVFilter):
base_field_class: type[BaseRangeField] = ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Sets lookup_expr and passes through
class LookupChoiceFilter(Filter):
field_class: type[forms.CharField]
outer_class: type[LookupChoiceField] = ...
empty_label: str | None
lookup_choices: list[tuple[str, str]] | None
def __init__(
self,
field_name: str | None = None,
lookup_choices: list[tuple[str, str]] | None = None,
field_class: type[Field] | None = None,
**kwargs: Any, # Handles empty_label and other field config
) -> None: ...
@classmethod
def normalize_lookup(cls, lookup: Any) -> tuple[Any, str]: ...
def get_lookup_choices(self) -> list[tuple[str, str]]: ...
@property
def field(self) -> Field: ...
lookup_expr: str
def filter(self, qs: QuerySet[Any], lookup: Any) -> QuerySet[Any]: ...
class OrderingFilter(BaseCSVFilter, ChoiceFilter):
field_class: type[BaseCSVField] # Inherits CSV field behavior for comma-separated ordering
descending_fmt: str
param_map: dict[str, str] | None
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for fields and field_labels config
def get_ordering_value(self, param: str) -> str: ...
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
@classmethod
def normalize_fields(cls, fields: Any) -> list[str]: ...
def build_choices(self, fields: Any, labels: dict[str, str] | None) -> list[tuple[str, str]]: ...
class FilterMethod:
f: Filter
def __init__(self, filter_instance: Filter) -> None: ...
def __call__(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ...
@property
def method(self) -> Callable[..., Any]: ...
@@ -0,0 +1,85 @@
from collections import OrderedDict
from enum import Enum
from typing import Any, ClassVar
from django.db import models
from django.db.models import Model, QuerySet
from django.forms import Form
from django.http import HttpRequest, QueryDict
from .filters import Filter
def remote_queryset(field: models.Field[Any, Any]) -> QuerySet[Any]: ... # Field type params vary by model definition
class UnknownFieldBehavior(Enum):
RAISE = "raise"
WARN = "warn"
IGNORE = "ignore"
class FilterSetOptions:
model: type[Model] | None
fields: list[str] | dict[str, list[str]] | str | None
exclude: list[str] | None
filter_overrides: dict[type[models.Field[Any, Any]], dict[str, Any]] # Field override mapping
form: type[Form]
unknown_field_behavior: UnknownFieldBehavior
def __init__(self, options: Any | None = None) -> None: ... # Meta options can be various configuration types
class FilterSetMetaclass(type):
# Class attrs vary by definition
def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> FilterSetMetaclass: ...
# Class attrs vary by definition
@classmethod
def get_declared_filters(cls, bases: tuple[type, ...], attrs: dict[str, Any]) -> OrderedDict[str, Filter]: ...
# Django field types vary widely - Any allows mapping all field types to their filters
FILTER_FOR_DBFIELD_DEFAULTS: dict[type[models.Field[Any, Any]], dict[str, Any]]
class BaseFilterSet:
FILTER_DEFAULTS: ClassVar[dict[type[models.Field[Any, Any]], dict[str, Any]]] = ... # Field type mapping
is_bound: bool
base_filters: OrderedDict[str, Filter]
declared_filters: OrderedDict[str, Filter]
data: QueryDict | dict[str, Any] | None # Filter input data values vary
queryset: QuerySet[Any] | None # Base queryset for any model type
request: HttpRequest | None
form_prefix: str | None
filters: OrderedDict[str, Filter]
def __init__(
self,
data: QueryDict | dict[str, Any] | None = None, # Filter data values vary
queryset: QuerySet[Any] | None = None, # Base queryset for any model
*,
request: HttpRequest | None = None,
prefix: str | None = None,
) -> None: ...
def is_valid(self) -> bool: ...
@property
def errors(self) -> dict[str, list[str]]: ...
def filter_queryset(self, queryset: QuerySet[Any]) -> QuerySet[Any]: ... # Works with any model type
@property
def qs(self) -> QuerySet[Any]: ... # Filtered queryset of any model
def get_form_class(self) -> type[Form]: ...
@property
def form(self) -> Form: ...
@classmethod
def get_fields(cls) -> dict[str, models.Field[Any, Any]]: ... # Model fields have varying type params
@classmethod
def get_filter_name(cls, field_name: str, lookup_expr: str) -> str: ...
@classmethod
def get_filters(cls) -> OrderedDict[str, Filter]: ...
@classmethod
def handle_unrecognized_field(cls, field_name: str, message: str) -> None: ...
@classmethod
def filter_for_field(
cls, field: models.Field[Any, Any], field_name: str, lookup_expr: str | None = None
) -> Filter: ... # Accepts any Django field type
@classmethod
def filter_for_lookup(cls, field: models.Field[Any, Any], lookup_type: str) -> type[Filter]: ... # Field type varies by model
class FilterSet(BaseFilterSet, metaclass=FilterSetMetaclass): ...
def filterset_factory(
model: type[Model], filterset: FilterSetMetaclass = ..., fields: list[str] | dict[str, list[str]] | str | None = None
) -> type[FilterSet]: ...
@@ -0,0 +1,3 @@
from .backends import DjangoFilterBackend as DjangoFilterBackend
from .filters import *
from .filterset import FilterSet as FilterSet
@@ -0,0 +1,30 @@
from typing import Any
from typing_extensions import TypeAlias
from django.db.models import QuerySet
from django.http import HttpRequest
from django_filters.filterset import FilterSetMetaclass
from . import filterset
# APIView placeholder - djangorestframework is optional, so we use Any for compatibility
_APIView: TypeAlias = Any
class DjangoFilterBackend:
filterset_base: FilterSetMetaclass = ...
raise_exception: bool
@property
def template(self) -> str: ...
# Works with any model type
def get_filterset(self, request: HttpRequest, queryset: QuerySet[Any], view: _APIView) -> filterset.FilterSet | None: ...
# Any model queryset
def get_filterset_class(self, view: _APIView, queryset: QuerySet[Any] | None = None) -> type[filterset.FilterSet] | None: ...
# Kwargs vary by filterset
def get_filterset_kwargs(self, request: HttpRequest, queryset: QuerySet[Any], view: _APIView) -> dict[str, Any]: ...
# Filters any model type
def filter_queryset(self, request: HttpRequest, queryset: QuerySet[Any], view: _APIView) -> QuerySet[Any]: ...
def to_html(self, request: HttpRequest, queryset: QuerySet[Any], view: _APIView) -> str: ... # Renders form for any model
@@ -0,0 +1,71 @@
from typing import Any
from ..filters import (
AllValuesFilter,
AllValuesMultipleFilter,
BaseCSVFilter,
BaseInFilter,
BaseRangeFilter,
BooleanFilter as _BaseBooleanFilter,
CharFilter,
ChoiceFilter,
DateFilter,
DateFromToRangeFilter,
DateRangeFilter,
DateTimeFilter,
DateTimeFromToRangeFilter,
DurationFilter,
Filter,
IsoDateTimeFilter,
IsoDateTimeFromToRangeFilter,
LookupChoiceFilter,
ModelChoiceFilter,
ModelMultipleChoiceFilter,
MultipleChoiceFilter,
NumberFilter,
NumericRangeFilter,
OrderingFilter,
RangeFilter,
TimeFilter,
TimeRangeFilter,
TypedChoiceFilter,
TypedMultipleChoiceFilter,
UUIDFilter,
)
__all__ = [
"AllValuesFilter",
"AllValuesMultipleFilter",
"BaseCSVFilter",
"BaseInFilter",
"BaseRangeFilter",
"BooleanFilter",
"CharFilter",
"ChoiceFilter",
"DateFilter",
"DateFromToRangeFilter",
"DateRangeFilter",
"DateTimeFilter",
"DateTimeFromToRangeFilter",
"DurationFilter",
"Filter",
"IsoDateTimeFilter",
"IsoDateTimeFromToRangeFilter",
"LookupChoiceFilter",
"ModelChoiceFilter",
"ModelMultipleChoiceFilter",
"MultipleChoiceFilter",
"NumberFilter",
"NumericRangeFilter",
"OrderingFilter",
"RangeFilter",
"TimeFilter",
"TimeRangeFilter",
"TypedChoiceFilter",
"TypedMultipleChoiceFilter",
"UUIDFilter",
]
# REST framework specific BooleanFilter that uses BooleanWidget by default
class BooleanFilter(_BaseBooleanFilter):
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Accepts any filter initialization params
@@ -0,0 +1,17 @@
from collections import OrderedDict
from typing import Any, ClassVar
from django.db import models
from django.forms import Form
from django_filters import filterset
from django_filters.filters import Filter
# REST framework field mappings support all Django field types
FILTER_FOR_DBFIELD_DEFAULTS: dict[type[models.Field[Any, Any]], dict[str, Any]]
class FilterSet(filterset.FilterSet):
FILTER_DEFAULTS: ClassVar[dict[type[models.Field[Any, Any]], dict[str, Any]]] = ... # DRF field mappings
base_filters: OrderedDict[str, Filter]
declared_filters: OrderedDict[str, Filter]
@property
def form(self) -> Form: ...
@@ -0,0 +1,36 @@
from collections.abc import Callable
from datetime import datetime
from typing import Any
from django.db import models
from django.db.models import Model
def deprecate(msg: str, level_modifier: int = 0) -> None: ...
class MigrationNotice(DeprecationWarning):
url: str
def __init__(self, message: str) -> None: ...
class RenameAttributesBase(type):
renamed_attributes: tuple[tuple[str, str, DeprecationWarning], ...] = ()
# Class attrs vary by definition
def __new__(metacls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> RenameAttributesBase: ...
def get_name(metacls, name: str) -> str: ...
def __getattr__(metacls, name: str) -> Any: ... # Attribute values vary by name and class
def __setattr__(metacls, name: str, value: Any) -> None: ... # Attribute values can be any type
def try_dbfield(
fn: Callable[[models.Field[Any, Any]], Any], field_class: type[models.Field[Any, Any]]
) -> Any: ... # Generic field operation
def get_all_model_fields(model: type[Model]) -> dict[str, models.Field[Any, Any]]: ... # Fields vary by model definition
def get_model_field(model: type[Model], field_name: str) -> models.Field[Any, Any]: ... # Field type unknown at static time
def get_field_parts(model: type[Model], field_name: str) -> list[models.Field[Any, Any]]: ... # Relationship fields vary
def resolve_field(
model_field: models.Field[Any, Any], lookup_expr: str
) -> tuple[models.Field[Any, Any], str]: ... # Generic field resolution
def handle_timezone(value: datetime, is_dst: bool | None = None) -> datetime: ...
def verbose_field_name(model: type[Model], field_name: str) -> str: ...
def verbose_lookup_expr(lookup_expr: str) -> str: ...
def label_for_filter(model: type[Model], field_name: str, lookup_expr: str, exclude: bool = False) -> str: ...
def translate_validation(error_dict: dict[str, list[str]]) -> dict[str, list[str]]: ...
@@ -0,0 +1,38 @@
from _typeshed import Unused
from typing import Any
from django.db.models import Model, QuerySet
from django.http import HttpRequest, HttpResponse
from django.views.generic import View
from django.views.generic.list import MultipleObjectMixin, MultipleObjectTemplateResponseMixin
from .constants import ALL_FIELDS
from .filterset import FilterSet
class FilterMixin:
filterset_class: type[FilterSet] | None
filterset_fields = ALL_FIELDS
strict: bool
def get_filterset_class(self) -> type[FilterSet] | None: ...
def get_filterset(self, filterset_class: type[FilterSet]) -> FilterSet: ...
def get_filterset_kwargs(self, filterset_class: type[FilterSet]) -> dict[str, Any]: ... # Filterset init params vary
def get_strict(self) -> bool: ...
class BaseFilterView(FilterMixin, MultipleObjectMixin[Any], View): # Generic model type
filterset: FilterSet
object_list: QuerySet[Any] # Filtered objects of any model type
def get(self, request: HttpRequest, *args: Unused, **kwargs: Unused) -> HttpResponse: ...
class FilterView(MultipleObjectTemplateResponseMixin, BaseFilterView):
template_name_suffix: str
def object_filter(
request: HttpRequest,
model: type[Model] | None = None,
queryset: QuerySet[Any] | None = None, # Base queryset for any model
template_name: str | None = None,
extra_context: dict[str, Any] | None = None, # Template context values vary
context_processors: list[Any] | None = None, # Context processors vary by implementation
filter_class: type[FilterSet] | None = None,
) -> HttpResponse: ...
@@ -0,0 +1,86 @@
from collections.abc import Mapping, Sequence
from typing import Any
from django import forms
from django.http import QueryDict
from django.utils.safestring import SafeString
class LinkWidget(forms.Widget):
# Choice values can be any type (int, str, Model, etc.)
choices: Sequence[tuple[Any, str]]
# Choice values can be any selectable type
def __init__(self, attrs: dict[str, Any] | None = None, choices: Sequence[tuple[Any, str]] = ()) -> None: ...
data: QueryDict | dict[str, Any]
# Return value depends on widget data type
def value_from_datadict(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> Any: ...
# Widget value and renderer can be any type, choices parameter combines with class choices
def render( # type: ignore[override]
self,
name: str,
value: Any,
attrs: dict[str, Any] | None = None,
choices: Sequence[tuple[Any, str]] = (),
renderer: Any | None = None,
) -> SafeString: ...
# Choice values and selections can be any type
def render_options(self, choices: Sequence[tuple[Any, str]], selected_choices: list[Any], name: str) -> str: ...
# Selected choices and option values can be any type
def render_option(self, name: str, selected_choices: list[Any], option_value: Any, option_label: str) -> str: ...
def option_string(self) -> str: ...
class SuffixedMultiWidget(forms.MultiWidget):
suffixes: list[str]
def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any widget params for MultiWidget
def suffixed(self, name: str, suffix: str) -> str: ...
# Widget value and context can contain any data types
def get_context(self, name: str, value: Any, attrs: dict[str, Any] | None) -> dict[str, Any]: ...
# Returns list of any value types from widget data
def value_from_datadict(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> list[Any]: ...
# Widget data can contain any types
def value_omitted_from_data(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> bool: ...
def replace_name(self, output: str, index: int) -> str: ...
# Decompresses any widget value into list of components
def decompress(self, value: Any) -> list[Any] | None: ...
class RangeWidget(SuffixedMultiWidget):
template_name: str
suffixes: list[str]
# Accepts any widget attribute types
def __init__(self, attrs: dict[str, Any] | None = None) -> None: ...
# Decompresses any range value into list components
def decompress(self, value: Any) -> list[Any] | None: ...
class DateRangeWidget(RangeWidget):
suffixes: list[str]
class LookupChoiceWidget(SuffixedMultiWidget):
suffixes: list[str]
# Decompresses any lookup choice value into components
def decompress(self, value: Any) -> list[Any] | None: ...
class BooleanWidget(forms.Select):
# Accepts any widget attribute types
def __init__(self, attrs: dict[str, Any] | None = None) -> None: ...
# Widget value and renderer can be any type
def render(self, name: str, value: Any, attrs: dict[str, Any] | None = None, renderer: Any | None = None) -> SafeString: ...
# Return value type depends on widget data
def value_from_datadict(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> Any: ...
class BaseCSVWidget(forms.Widget):
# Can be widget class or instance - __init__ converts to instance via instantiation or deepcopy
surrogate: type[Any] = ...
# Args/kwargs can be any widget params for surrogate init
def __init__(self, *args: Any, **kwargs: Any) -> None: ...
# CSV widget data can contain any types
def value_from_datadict(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> list[str]: ...
# Widget value and renderer can be any type
def render(self, name: str, value: Any, attrs: dict[str, Any] | None = None, renderer: Any | None = None) -> SafeString: ...
class CSVWidget(BaseCSVWidget, forms.TextInput):
# Args/kwargs can be any widget params, attrs for styling
def __init__(self, *args: Any, attrs: dict[str, Any] | None = None, **kwargs: Any) -> None: ...
class QueryArrayWidget(BaseCSVWidget, forms.TextInput):
# Query array widget data can contain any types
def value_from_datadict(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> list[str]: ...