モデルマネージャーにオブジェクトを取得するように依頼すると、一致するオブジェクトがないときにDoesNotExist
が発生します。
go = Content.objects.get(name="baby")
DoesNotExist
の代わりに、どのようにgo
をNone
にできますか?
これを行うための「組み込み」の方法はありません。 Djangoは、毎回DoesNotExist例外を発生させます。 pythonでこれを処理する慣用的な方法は、try catchでラップすることです:
try:
go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
go = None
私がやったことは、models.Managerをサブクラス化し、上記のコードのようなsafe_get
を作成し、そのマネージャーをモデルに使用することです。そうすれば、SomeModel.objects.safe_get(foo='bar')
と書くことができます。
Django 1.6以降では、 first() メソッドを次のように使用できます。
Content.objects.filter(name="baby").first()
get()
は、指定されたパラメーターのオブジェクトが見つからない場合にDoesNotExist
例外を発生させます。この例外は、モデルクラスの属性でもあります。DoesNotExist
例外はDjango.core.exceptions.ObjectDoesNotExist
から継承します
例外をキャッチして、None
を割り当てることができます。
from Django.core.exceptions import ObjectDoesNotExist
try:
go = Content.objects.get(name="baby")
except ObjectDoesNotExist:
go = None
このための汎用関数を作成できます。
def get_or_none(classmodel, **kwargs):
try:
return classmodel.objects.get(**kwargs)
except classmodel.DoesNotExist:
return None
以下のようにこれを使用してください:
go = get_or_none(Content,name="baby")
一致するエントリがない場合、goはNoneになります。それ以外の場合、Contentエントリが返されます。
注:name = "baby"に対して複数のエントリが返された場合、例外MultipleObjectsReturnedが発生します。
次の方法で実行できます。
go = Content.objects.filter(name="baby").first()
Go変数は、必要なオブジェクトまたはNoneになります
参照: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#Django.db.models.query.QuerySet.first
物事を簡単にするために、ここに素晴らしい返信からの入力に基づいて、私が書いたコードのスニペットがあります:
class MyManager(models.Manager):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except ObjectDoesNotExist:
return None
そして、あなたのモデルで:
class MyModel(models.Model):
objects = MyManager()
それでおしまい。これで、MyModel.objects.get()とMyModel.objetcs.get_or_none()ができました。
フィルターでexists
を使用できます。
Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS
存在するかどうかだけを知りたい場合の代替手段
迷惑な関数 の1つで、再実装したくない場合があります。
from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")
ビューのさまざまなポイントで例外を処理するのは非常に面倒な場合があります。
class ContentManager(model.Manager):
def get_nicely(self, **kwargs):
try:
return self.get(kwargs)
except(KeyError, Content.DoesNotExist):
return None
そして、それをコンテンツモデルクラスに含めます
class Content(model.Model):
...
objects = ContentManager()
このようにして、ビューで簡単に処理できます。
post = Content.objects.get_nicely(pk = 1)
if post:
# Do something
else:
# This post doesn't exist
例外処理、条件ステートメント、またはDjango 1.6+の要件を含まないシンプルな1行のソリューションが必要な場合は、代わりにこれを実行します。
x = next(iter(SomeModel.objects.filter(foo='bar')), None)
get_object_or_404()
を使用するのは悪い考えではないと思います
from Django.shortcuts import get_object_or_404
def my_view(request):
my_object = get_object_or_404(MyModel, pk=1)
この例は次と同等です:
from Django.http import Http404
def my_view(request):
try:
my_object = MyModel.objects.get(pk=1)
except MyModel.DoesNotExist:
raise Http404("No MyModel matches the given query.")
Djangoオンラインドキュメントでget_object_or_404()の詳細を読むことができます。
.DoesNotExist
という名前のモデルに添付されたDjango組み込み例外を使用できます。したがって、ObjectDoesNotExist
例外をインポートする必要はありません。
代わりに:
from Django.core.exceptions import ObjectDoesNotExist
try:
content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
content = None
できるよ:
try:
content = Content.objects.get(name="baby")
except Content.DoesNotExist:
content = None
Django 1.7以降では、次のことができます。
class MyQuerySet(models.QuerySet):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except self.model.DoesNotExist:
return None
class MyBaseModel(models.Model):
objects = MyQuerySet.as_manager()
class MyModel(MyBaseModel):
...
class AnotherMyModel(MyBaseModel):
...
「MyQuerySet.as_manager()」の利点は、次の両方が機能することです。
MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()
モデルのQuerySet
オブジェクトクエリセット以外のクエリセット(存在する場合)から一意のオブジェクト(存在する場合)を取得したい場合に、オプションでall
インスタンスを渡すことができるヘルパー関数のバリエーションがあります親インスタンスへ):
def get_unique_or_none(model, queryset=None, **kwargs):
"""
Performs the query on the specified `queryset`
(defaulting to the `all` queryset of the `model`'s default manager)
and returns the unique object matching the given
keyword arguments. Returns `None` if no match is found.
Throws a `model.MultipleObjectsReturned` exception
if more than one match is found.
"""
if queryset is None:
queryset = model.objects.all()
try:
return queryset.get(**kwargs)
except model.DoesNotExist:
return None
これは、次の2つの方法で使用できます。
obj = get_unique_or_none(Model, **kwargs)
前に説明したようにobj = get_unique_or_none(Model, parent.children, **kwargs)
例外なく:
if SomeModel.objects.filter(foo='bar').exists():
x = SomeModel.objects.get(foo='bar')
else:
x = None
例外を使用する:
try:
x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
x = None
Pythonで例外を使用するタイミングについては、少し議論があります。一方では、「許可よりも許しを求める方が簡単です」。私はこれに同意しますが、例外はそのまま残り、「理想的なケース」はヒットせずに実行されるべきだと思います。