Аннотация динамического типа для пользовательского метода менеджеров моделей Django
Мне нужна помощь с подсказкой типа для метода пользовательского менеджера моделей.
Это мой пользовательский менеджер и базовая модель. Я наследую эту базовую модель для других моделей, чтобы не писать общие поля снова и снова.
class BaseManager(models.Manager):
def get_or_none(self, *args, **kwargs):
try:
return self.get(*args, **kwargs)
except self.model.DoesNotExist:
return None
class BaseModel(models.Model):
id = models.UUIDField(
primary_key=True, default=uuid.uuid4, verbose_name="ID", editable=False
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = BaseManager() # Set the custom manager
class Meta:
abstract = True
Это пример модели:
class MyModel(BaseModel):
category = models.CharField(max_length=10)
Теперь об этом:
my_object = MyModel.objects.get_or_none(
category="...",
)
Аннотация типа выглядит следующим образом, когда я навожу курсор в IDE:
my_object: BaseModel | None = MyModel.objects. get_or_none(...
Но я хочу, чтобы аннотация типа выглядела следующим образом:
my_object: MyModel | None = MyModel.objects. get_or_none(...
Как я могу это сделать? Это работает для методов по умолчанию, таких как get и filter. Но как сделать это для пользовательских методов, таких как get_or_none?
Пожалуйста, помогите мне.
Спасибо
Для того чтобы ваша IDE видела get_or_none
метод, вы должны добавить аннотацию типа к objects
переменной в вашем BaseModel
классе, как например:
objects: BaseManager = BaseManager()
Python's type inference system can not interfere this, because the code works a bit too much with meta-programming, etc. and the interpreter can not «get through» that (yet). For example a package like django-stubs
[GitHub] contains type hints that help the type checker to understand the types.
Тогда выглядит так: [GitHub]:
from typing_extensions import Self class Model(metaclass=ModelBase): # … objects: ClassVar[Manager[Self]]
Если вы включите поддержку Django в PyCharm, PyCharm обычно устанавливает django-stubs
за шторками, чтобы помочь вам с этими проверками типов.
Таким образом, они переписали тип Manager
, чтобы убедиться, что его можно подписать типом модели, с которой работает менеджер.
Вы можете добавить файл .pyi
, в котором содержится подсказка:
# path/to/base/manager.pyi
from typing import Generic, Tuple, TypeVar
from django.db.models.base import Model
from django.db.models.manager import Manager
_T = TypeVar('_T', bound=Model, covariant=True)
class BaseManager(Generic[_T], Manager[_T]):
def get_or_none(self, *args, **kwargs) -> _T | None: …
и убедитесь, что _T
содержит ссылку на модель с:
# path/to/base/model.pyi
from typing import ClassVar
from django.db.models.base import Model
from path.to.base.manager import BaseManager
from typing_extensions import Self
class BaseModel(Model):
objects: ClassVar[OrderHistoryManager[Self]]
Обычно PyCharm подбирает подсказки типов.