Djangoタイプヒントを使用してPython QuerySetのレコードタイプを指定することはできますか? QuerySet[SomeModel]
のようなものですか?
たとえば、次のモデルがあります。
class SomeModel(models.Model):
smth = models.IntegerField()
そして、そのモデルのQuerySetをfuncのparamとして渡します:
def somefunc(rows: QuerySet):
pass
しかし、List[SomeModel]
のように、QuerySetでレコードのタイプを指定する方法:
def somefunc(rows: List[SomeModel]):
pass
しかし、QuerySetで?
1つの解決策は、Union型付けクラスを使用することです。
from typing import Union, List
from Django.db.models import QuerySet
from my_app.models import MyModel
def somefunc(row: Union[QuerySet, List[MyModel]]):
pass
row
引数をスライスすると、返された型がMyModelの別のリストまたはMyModelのインスタンスであることがわかります。また、QuerySet
クラスのメソッドがrow
引数も。
一般的な型のヒントを取得するために、このヘルパークラスを作成しました。
from Django.db.models import QuerySet
from typing import Iterator, Union, TypeVar, Generic
T = TypeVar("T")
class ModelType(Generic[T]):
def __iter__(self) -> Iterator[Union[T, QuerySet]]:
pass
次に、次のように使用します。
def somefunc(row: ModelType[SomeModel]):
pass
これにより、このタイプを使用するたびにノイズが減少し、モデル間で使用可能になります(ModelType[DifferentModel]
)。
これはOr Duanの改善されたヘルパークラスです。
_from Django.db.models import QuerySet
from typing import Iterator, TypeVar, Generic
_Z = TypeVar("_Z")
class QueryType(Generic[_Z], QuerySet):
def __iter__(self) -> Iterator[_Z]: ...
_
このクラスは、クエリでQuerySet
を使用する場合など、filter
オブジェクト専用に使用されます。
サンプル:
_from some_file import QueryType
sample_query: QueryType[SampleClass] = SampleClass.objects.filter(name=name)
_
インタープリターは_sample_query
_をQuerySet
オブジェクトとして認識し、count()
などの提案を取得し、オブジェクトをループしながら、SampleClass
の提案を取得します。
注
このタイプのヒンティングの形式は、_python3.6
_以降で利用できます。
Django専用のヒントクラスを持つ Django_hint も使用できます。
私もこれに対する解決策を探しています。 Django Developersリストには thread があり、そこでそのような機能を実装する方法を議論しています。
現在、彼らは mypyのDjango拡張機能 を開発していますが、特定のリクエストに対しては運が悪いようです。 「Provably Never」という見出しの下のロードマップで:
クエリセットは部分的にサポートされている場合がありますが、複雑な引数(フィルタおよび取得クエリの引数など)またはQおよびFオブジェクトは、mypyの表現可能性を超えています。
それを述べると、条件が改善するまでプレーンole QuerySet
を使用する必要があります。
Django
コードを入力するためのDjango-stubs
(名前 PEP561
に続く )と呼ばれる特別なパッケージがあります。
それがどのように機能するかです:
# server/apps/main/views.py
from Django.http import HttpRequest, HttpResponse
from Django.shortcuts import render
def index(request: HttpRequest) -> HttpResponse:
reveal_type(request.is_ajax)
reveal_type(request.user)
return render(request, 'main/index.html')
出力:
» PYTHONPATH="$PYTHONPATH:$PWD" mypy server
server/apps/main/views.py:14: note: Revealed type is 'def () -> builtins.bool'
server/apps/main/views.py:15: note: Revealed type is 'Django.contrib.auth.models.User'
モデルとQuerySet
sの場合:
# server/apps/main/logic/repo.py
from Django.db.models.query import QuerySet
from server.apps.main.models import BlogPost
def published_posts() -> 'QuerySet[BlogPost]': # works fine!
return BlogPost.objects.filter(
is_published=True,
)
出力:
reveal_type(published_posts().first())
# => Union[server.apps.main.models.BlogPost*, None]