1

このモデルがあるとします:

class PhotoAlbum(models.Model):
    title = models.CharField(max_length=128)
    author = models.CharField(max_length=128)

class Photo(models.Model):
    album = models.ForeignKey('PhotoAlbum')

「名前が「The」で始まるアルバムを 10 個見つけて、それらのアルバムのすべての写真を教えてください」というクエリを実行します。

SQLでは、次のようにすることができます:

SELECT * FROM
    (SELECT * FROM photoalbum WHERE title LIKE 'The%' LIMIT 10) AS selected_albums
LEFT JOIN photo ON photo.album_id = selected_albums.id

私の質問は、Djangoでこれを行うにはどうすればよいですか? (アルバムごとにクエリをトリガーする必要はありません!)これはかなり一般的な要件であると思いますが、それを行う方法がないとは信じられません。

Django-ey の方法がない場合は、「生の SQL を使用して Django でこれを実装するにはどうすればよいですか?」に落ち着きます。

動作しないものを次に示します。

  • select_related(); これは前方の ForeignKey関係であり、これは後方の関係です。
  • prefetch_related(); 前向きな関係にも。編集:実際、これはうまくいきます!少なくとも 1 レベルのForeignKeys。
  • PhotoAlbum.photo_set; これにより、各アルバムのクエリがトリガーされます。
  • 私が持っている最も近いものは次のとおりです。

    アルバム = PhotoAlbum.objects.all()[:10] 写真 = Photo.objects.filter(album__in=albums)

しかし、悲しいことに、MySQL では動作しません。これが作成する型クエリLEFT JOINよりも 'sを使用するほうがよいと言われました。WHERE ... IN (SELECT ...)

編集

この問題に関する 3 年前のメーリング リストの投稿を見つけました。そこに解決策はありません。

彼らはそれを修正しないと言っている6年前のバグレポート。「そういうわけにはいかない」以外の理由はありません。どうやらRoRでも可能です。

4

3 に答える 3

4

Django 1.4+ では、以下を使用できますprefetch_related

PhotoAlbum.objects.filter(title__startswith='The').prefetch_related('photo')[:10]

より古いバージョンでは、 django-batch-select を試してください。

アップデート

ごめん。私はまだ主に 1.3 を使用しているため、prefetch_relatedあまり使用していません。他のすべてのクエリ タイプでは、付録を含めませんが_set、Django は明らかにここで規則を破っています。を使えばうまくいきますprefetch_related('photo_set')

複数のものを取得する必要がある場合は、 の場合と同じようにフィールドをリストできますselect_related。つまり、次のようになります。

prefetch_related('something', 'something_else', 'foo')

ただし、ドキュメントのこの部分に細心の注意を払ってください。

また、QuerySet の場合と同様に、別のデータベース クエリを意味する後続の連鎖メソッドは、以前にキャッシュされた結果を無視し、新しいデータベース クエリを使用してデータを取得することにも注意してください。したがって、次のように書くと:

   >>> pizzas = Pizza.objects.prefetch_related('toppings')
   >>> [list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]

...次に、pizza.toppings.all() がプリフェッチされているという事実は役に立ちません。実際、使用していないデータベース クエリを実行したため、パフォーマンスが低下します。したがって、この機能は注意して使用してください。

于 2012-07-31T18:07:53.383 に答える
1

これは機能し、2 つのクエリのみを実行します。prefetch_related は逆 FK に対して機能します。実際には、それが作成された目的です。

for album in PhotoAlbum.objects.filter(title__startswith='The').prefetch_related('photo_set')[:10]:
    print album.photo_set.all()
于 2012-07-31T20:30:58.413 に答える
0

すべての PhotoAlbum で photo_set をトリガーしたくありませんよね? 指定されたものだけ?

for p in PhotoAlbum.objects.filter(title__startswith='The'):
    p.photo_set.all()
于 2012-07-31T20:06:43.137 に答える