3

次のような複数テーブルの継承スキーマがあります。

class NodeData(models.Model):
    node = models.ForeignKey(Node, db_index = True)
    value = models.FloatField(default = 0)
    name = models.TextField(unique=True, blank=True)

class Node(models.Model):
    name = models.CharField(max_length=50, blank=True)
    description = models.TextField(blank=True)
    node_tree = models.ForeignKey(NodeTree, db_index = True)
    unique_name = models.TextField(unique=True, blank=True)
    last_updated_timestamp = models.DateTimeField('date last updated', blank=True)

class ConceptNode(Node):
    node_parent = models.ForeignKey(Node, related_name="nodeParent", null=True, blank=True)

class DerivedNode(Node):
    node_source = models.ForeignKey(Node, related_name="nodeSource")
    node_target = models.ForeignKey(Node, related_name="nodeTarget")

パフォーマンス上の理由から、大量の NodeData 要素をフェッチするときは常に select_related(depth = 2) を使用しています。ただし、select_related はリレーションをサブクラスまでたどらないため、次のコード* は myFunction の ConceptNode 実装を呼び出し、その関数で使用される ConceptNode オブジェクトのプリフェッチ データはありません。

nd = NodeData.objects.get(id = 1)
nd.node.conceptnode.myFunction()

これにより、select_related はあまり役に立ちません。この方法で呼び出される関数がたくさんあり、select_related によってキャッシュされたデータの利点を享受していないからです。

私の質問は: select_related を取得してこの情報を取得し、取得した各 NodeData オブジェクトに Node と ConceptNode/DerivedNode インスタンスの両方がキャッシュされるようにすることはできますか?*

注: これは、ここで質問したように、アクセサー関数モデルを使用して実際に行われます

注: 私がやろうとしていることはこれに似ていますが、複数のサブクラスがあるため、少し異なります。

編集: chris-platt からのヒントのおかげで、次のことが必要なことを行うことがわかりました:

nd = NodeData.objects.select_related('conceptnode','derivednode').get(id = 1)
nd.node.conceptnode.myFunction()

最初の行は、DerivedNode または ConceptNode インスタンスを関連するキャッシュ オブジェクトにプリフェッチします。

4

2 に答える 2

2

のようなことをするConceptNode.objects.get(...)と、Nodeインスタンスが同時にフェッチされるため、インスタンスの完全なデータが得られます。ただし、サブクラスなどNode.objects.get(...)からのデータのようなものは含まれません。これらを選択するには、 を使用する必要があり、複数のサブクラスを取得するには、コンマ区切りのリストとして s を追加し続けるだけです。ConceptNodeselect_related(<related_name>)related_name

Node.objects.select_related('nodeParent', 'nodeSource', 'nodeTarget')
于 2012-07-27T22:02:13.397 に答える
0

ここで、どのように機能するかについて少し誤解があると思いますselect_related。すべてのリレーションシップで機能するわけではありません。外部キーまたは 1 対 1 のリレーションシップで機能します。関連データが単一のレコードであり、結合を使用して元のクエリを変更して取得できる場合です。したがって、この例は機能しません。

nd = NodeData.objects.get(id = 1)
nd.node.conceptnode.myFunction()

... Node は ConceptNode の親であるため、それらの多くを関連付けることができます。実際、 . で属性エラーが発生すると思いますnd.node.conceptnode。次のような方法で子の ConceptNode にアクセスすると思います。

nd = NodeData.objects.get(id = 1)
nd.node.nodeParent.all() # Loop through this and do stuff with the children...

を設定したので、ここでは「nodeParent」を使用していますrelated_name(「nodeChildren」など、より適切なものに変更したい場合があります) が、デフォルトでは「conceptnode_set」になります。nd.node.conceptnode_set.all()

Django 1.4 を使用している場合[prefetch_related][1]、私は使用していない という新しい QuerySet メソッドがありますが、おそらくこの正確な状況 (「多」型の関係のクエリを削減する) のためのものであり、理論的にはできるはずです。何かのようなもの:

nd = NodeData.objects.get(id = 1).prefetch_related('conceptnode')

...ただし、「conceptnode」引数と、一般に prefetch_related を使用して、必要なものが得られるかどうかを確認する必要があります。

于 2012-07-27T22:29:02.790 に答える