web-dev-qa-db-ja.com

djangoのクエリセットから最初のオブジェクトを取得する最も速い方法は?

Djangoのクエリセットから最初のオブジェクトを取得するか、存在しない場合はNoneを返したいと思うことがよくあります。これを行うには多くの方法がありますが、すべてうまくいきます。しかし、私はどちらが最もパフォーマンスが高いのだろうかと思っています。

qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
    return qs[0]
else:
    return None

これにより、2つのデータベース呼び出しが発生しますか?それはもったいないようです。これは速いですか?

qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
    return qs[0]
else:
    return None

別のオプションは次のとおりです。

qs = MyModel.objects.filter(blah = blah)
try:
    return qs[0]
except IndexError:
    return None

これにより、単一のデータベース呼び出しが生成されます。これは適切です。ただし、例外オブジェクトを長時間作成する必要があります。これは、本当に必要なのが些細なifテストだけである場合に実行する非常にメモリ集約的な作業です。

単一のデータベース呼び出しだけで、例外オブジェクトでメモリを乱すことなくこれを行うにはどうすればよいですか?

170
Leopd

Django 1.6(2013年11月リリース) 導入 便利なメソッドfirst()およびlast()は、結果の例外を飲み込み、クエリセットがオブジェクトを返さない場合にNoneを返します。

297
cod3monk3y

正解は

Entry.objects.all()[:1].get()

以下で使用できます

Entry.objects.filter()[:1].get()

すべてのレコードの完全なデータベース呼び出しを強制するため、最初にリストに変換したくないでしょう。上記を実行するだけで、最初のものだけがプルされます。 .order_byを使用して、必要なものを最初に取得することもできます。

.get()を必ず追加してください。追加しないと、オブジェクトではなくQuerySetが返されます。

134
stormlifter
r = list(qs[:1])
if r:
  return r[0]
return None

現在、Django 1.9には、クエリセット用のfirst()メソッドがあります。

YourModel.objects.all().first()

これは、.get()[0]よりも優れた方法です。クエリセットが空の場合は例外をスローしないため、exists()を使用して確認する必要はありません。

29
levi

最初の要素を頻繁に取得する場合は、QuerySetを次の方向に拡張できます。

class FirstQuerySet(models.query.QuerySet):
    def first(self):
        return self[0]


class ManagerWithFirstQuery(models.Manager):
    def get_query_set(self):
        return FirstQuerySet(self.model)

次のようなモデルを定義します。

class MyModel(models.Model):
    objects = ManagerWithFirstQuery()

そして、次のように使用します。

 first_object = MyModel.objects.filter(x=100).first()
7
Nikolay Fominyh

こんな感じ

obj = model.objects.filter(id=emp_id)[0]

または

obj = model.objects.latest('id')
5
Nauman Tariq

これも機能します:

def get_first_element(MyModel):
    my_query = MyModel.objects.all()
    return my_query[:1]

空の場合は空のリストを返し、そうでない場合はリスト内の最初の要素を返します。

3
Nick Cuevas

既存のようなDjangoメソッドを使用する必要があります。それを使用するためにそこに。

if qs.exists():
    return qs[0]
return None
3
Ari

Django 1.6以降では、次のようにfirst()メソッドでfilter()を使用できます。

Model.objects.filter(field_name=some_param).first()
0
dtar