1

私はこのような2つのモデルを持っています:

class ClassA(models.Model):
    ida = models.AutoField(primary_key=True)
    classb = models.ForeignKey(ClassB)
    name = models.CharField(max_length=765)

class ClassB(models.Model):
    idb = models.AutoField(primary_key=True)
    name = models.CharField(max_length=765)

見出しClassAの下にグループ化されたすべてのオブジェクトのリストを表示したいと考えています。ClassBこれは私が持っているビューです:

def show_class_a_objects(request):
    class_b_objects = ClassB.objects.all().order_by('name')
    class_a_objects = ClassA.objects.all().order_by('name')
    return render_to_response('show_objects.html', {
        'class_a_objects': class_a_objects, 'class_a_objects': class_a_objects, 
    })

私のshow_objects.htmlファイルは次のようになります。

{% extends "base_show.html" %}
{% block content %}
</p>
<table>
<th align="left">Name</th>
{% for b in class_b_objects %}
    <tr>
    <td>{{b.name}}</td>
    </tr>
    {% for a in class_a_objects %}
        {% ifequal a.classb b %}
        <tr>
        <td><a href="{{ a.get_absolute_url }}">{{a.name}}</a></td>
        </tr>
        {% endifequal %}
    {% endfor %}
{% endfor %}
</table>
</br>
{% endblock %}

ネストされた 2 つの for ループを使用する代わりに、これを行うより良い方法はありますか?

4

3 に答える 3

1

逆の関係を介しての各セットにアクセスすることによって生成される多数のクエリを回避するにはA、次のようにします。

>>> from itertools import groupby
>>> alla = ClassA.objects.filter().order_by('classb').select_related('classb')
>>> groups = []
>>> for key,group in groupby(alla, lambda a: a.classb_id):
...     groups.append(list(group))

これで、イテラブルのイテラブルができました。1つのクエリを実行するだけでよいという理由だけで、外部キーを持つクラスに焦点を当てています(これはより複雑ですが、長期的には節約できる可能性があります)。上で起こっていることは、のリストをでソートしA、次に各リストをそれ自身のリスト/反復可能Bファイルに保存しているということです。にアクセスできるAので、を繰り返すことを心配する必要はありません。ABB

>>> for g in groups:
...     print g[0].classb # this is your grouping/header
...     print g           # this is a list of your classa instances

ジェネレーターの反復を減らしたい場合は少し凝ったものにすることができますが、を使用してモデルに焦点を当てることForeignKeyで、ビューのコードがより複雑になる代わりに、SQLのパフォーマンスが大幅に向上することがわかりました。多数のSQLクエリがアプリケーションの死に至る可能性があるため、複雑さは(IMO)無視できます。

于 2012-06-28T03:22:43.743 に答える
1
def show_class_a_objects(request):
    class_b_objects = ClassB.objects.all().order_by('name')
    class_a_objects = ClassA.objects.all().order_by('name')

必要なグループ化を実現するために、このように ClassA オブジェクトをクエリする必要はありません。ClassA -> ClassB で ForeignKey を作成すると、ClassB には、ClassB を ForeignKey として持つすべての ClassA オブジェクトを返すリレーションが含まれます。

見る

def show_class_a_objects(request):
    class_b_objects = ClassB.objects.all().order_by('name')
    return render_to_response('show_objects.html', {
        'class_b_objects': class_b_objects, 
    })

テンプレート

{% for b in class_b_objects %}
    <tr>
    <td>{{b.name}}</td>
    </tr>
    {% for a in b.classa_set.all %}
        <tr>
        <td><a href="{{ a.get_absolute_url }}">{{a.name}}</a></td>
        </tr>
    {% endfor %}
{% endfor %}

ネストされた for ループは引き続き必要ですが、適切なクラスを見つけるために、他のすべてのクラスの範囲全体をループして比較を行う必要はなくなりました。

もう少し制御が必要な場合は、これをビューに再度移動して、辞書を事前に構築する必要があります。

見る

def show_class_a_objects(request):
    class_b = ClassB.objects.all().order_by('name')
    class_b_objects = [(b, b.classa_set.all().order_by('name')) for b in class_b]
    return render_to_response('show_objects.html', {
        'class_b_objects': class_b_objects
    })

テンプレート

{% for b, a_list in class_b_objects %}
    <tr>
    <td>{{b.name}}</td>
    </tr>
    {% for a in a_list %}
        <tr>
        <td><a href="{{ a.get_absolute_url }}">{{a.name}}</a></td>
        </tr>
    {% endfor %}
{% endfor %}

更新: クエリ数の削減

コメントによると、データベース クエリの量を元の 2 から の量に増やすという問題に対処したかったのです1 + num_of_classb_objects。これは、元の ClassB クエリが 1 であるのに対し、各b.classa_set.all()リレーション コールは、関連する ClassA インスタンスを取得するための別のクエリであるためです。

別の方法を試してテストしたい場合は、効率的な逆引き参照に関するこのブログ投稿をチェックしてください。

例(モデル名へのリンクから適応):

qs = ClassB.objects.all()
obj_dict = dict([(obj.id, obj) for obj in qs])
objects = ClassA.objects.filter(classb__in=qs)
relation_dict = {}
for obj in objects:
    relation_dict.setdefault(obj.classb_id, []).append(obj)
for id, related_items in relation_dict.items():
    obj_dict[id]._related_items = related_items

また、django >= 1.4 を実行している場合、この機能はprefetch_related.

n+1私はこれをテストしていませんが、クエリが受け入れられない場合に調べるものとして提示したかったのです.

于 2012-06-28T01:56:47.157 に答える
0

おそらくManyToManyField()class Bモデルに複数のclass Aオブジェクトをすべての に含めることができますobject Bclass Aという同じ値を持つすべてのオブジェクトを取得するには、そのフィールドを呼び出すだけで済みますclass B

于 2012-06-28T01:54:58.023 に答える