Fix incorrect instance arg for BaseInlineFormSet.__init__ (#928)

* Fix BaseInlineFormSet generic to retain parent model class info

* Add in test for generic formset improvements
This commit is contained in:
Chris Beaven
2022-04-19 17:59:50 +12:00
committed by GitHub
parent 30bf4dab6c
commit a1b647700b
3 changed files with 29 additions and 7 deletions

View File

@@ -296,7 +296,7 @@ _ParentModelT = TypeVar("_ParentModelT", bound=Model)
class InlineModelAdmin(Generic[_ChildModelT, _ParentModelT], BaseModelAdmin[_ChildModelT]):
model: Type[_ChildModelT] = ...
fk_name: Optional[str] = ...
formset: Type[BaseInlineFormSet[_ChildModelT, forms.ModelForm[_ChildModelT]]] = ...
formset: Type[BaseInlineFormSet[_ChildModelT, _ParentModelT, forms.ModelForm[_ChildModelT]]] = ...
extra: int = ...
min_num: Optional[int] = ...
max_num: Optional[int] = ...
@@ -318,7 +318,7 @@ class InlineModelAdmin(Generic[_ChildModelT, _ParentModelT], BaseModelAdmin[_Chi
def get_max_num(self, request: HttpRequest, obj: Optional[_ParentModelT] = ..., **kwargs: Any) -> Optional[int]: ...
def get_formset(
self, request: HttpRequest, obj: Optional[_ParentModelT] = ..., **kwargs: Any
) -> Type[BaseInlineFormSet[_ChildModelT, forms.ModelForm[_ChildModelT]]]: ...
) -> Type[BaseInlineFormSet[_ChildModelT, _ParentModelT, forms.ModelForm[_ChildModelT]]]: ...
def get_queryset(self, request: HttpRequest) -> QuerySet[_ChildModelT]: ...
def has_add_permission(self, request: HttpRequest, obj: Optional[_ParentModelT]) -> bool: ... # type: ignore
def has_change_permission(self, request: HttpRequest, obj: Optional[_ParentModelT] = ...) -> bool: ... # type: ignore

View File

@@ -50,6 +50,7 @@ _ErrorMessages = Dict[str, Dict[str, str]]
_FormFieldCallback = Callable[[models.Field], Field]
_M = TypeVar("_M", bound=Model)
_ParentM = TypeVar("_ParentM", bound=Model)
def construct_instance(
form: BaseForm, instance: _M, fields: Optional[Container[str]] = ..., exclude: Optional[Container[str]] = ...
@@ -187,8 +188,8 @@ def modelformset_factory(
can_delete_extra: bool = ...,
) -> Type[BaseModelFormSet[_M, _ModelFormT]]: ...
class BaseInlineFormSet(BaseModelFormSet[_M, _ModelFormT]):
instance: Model = ...
class BaseInlineFormSet(Generic[_M, _ParentM, _ModelFormT], BaseModelFormSet[_M, _ModelFormT]):
instance: _ParentM
save_as_new: bool = ...
unique_fields: Collection[str] = ...
fk: ForeignKey # set by inlineformset_set
@@ -196,7 +197,7 @@ class BaseInlineFormSet(BaseModelFormSet[_M, _ModelFormT]):
self,
data: Optional[_DataT] = ...,
files: Optional[_FilesT] = ...,
instance: Optional[_M] = ...,
instance: Optional[_ParentM] = ...,
save_as_new: bool = ...,
prefix: Optional[str] = ...,
queryset: Optional[QuerySet[_M]] = ...,
@@ -210,7 +211,7 @@ class BaseInlineFormSet(BaseModelFormSet[_M, _ModelFormT]):
def get_unique_error_message(self, unique_check: Sequence[str]) -> str: ...
def inlineformset_factory(
parent_model: Type[Model],
parent_model: Type[_ParentM],
model: Type[_M],
form: Type[_ModelFormT] = ...,
formset: Type[BaseInlineFormSet] = ...,
@@ -233,7 +234,7 @@ def inlineformset_factory(
field_classes: Optional[Mapping[str, Type[Field]]] = ...,
absolute_max: Optional[int] = ...,
can_delete_extra: bool = ...,
) -> Type[BaseInlineFormSet[_M, _ModelFormT]]: ...
) -> Type[BaseInlineFormSet[_M, _ParentM, _ModelFormT]]: ...
class InlineForeignKeyField(Field):
disabled: bool

View File

@@ -0,0 +1,21 @@
- case: inlineformset_factory
main: |
from typing import Any, Type
from django import forms
from myapp.models import Article, Category
ArticleFS: Type[forms.BaseInlineFormSet[Article, Category, Any]] = forms.inlineformset_factory(Category, Article)
ArticleFS(instance=Article()) # E: Argument "instance" to "BaseInlineFormSet" has incompatible type "Article"; expected "Optional[Category]"
fs = ArticleFS(instance=Category())
reveal_type(fs.instance) # N: Revealed type is "myapp.models.Category*"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Article(models.Model):
pass
class Category(models.Model):
pass