モデルインスタンスからManagerにアクセスできません


83

別のインスタンスでモデルオブジェクトインスタンスを取得しようとしていますが、このエラーが発生します:

 Manager isn't accessible via topic instance

これが私のモデルです:

class forum(models.Model):
    # Some attributs

class topic(models.Model):
    # Some attributs

class post(models.Model):
    # Some attributs

    def delete(self):
        forum = self.topic.forum
        super(post, self).delete()
        forum.topic_count = topic.objects.filter(forum = forum).count()

これが私の見解です:

def test(request, post_id):
    post = topic.objects.get(id = int(topic_id))
    post.delete()

そして私は得る:

post.delete()
forum.topic_count = topic.objects.filter(forum = forum).count()
Manager isn't accessible via topic instances

回答:


122

問題のエラーManagerは、モデルのインスタンスを介してモデルのにアクセスしようとしたときに発生します。小文字のクラス名を使用しました。これにより、エラーの原因がインスタンスにアクセスしているManagerかどうかを判断するのが難しくなります。このエラーを引き起こす可能性のある他のシナリオは不明であるtopicためtopic、クラスではなくモデルのインスタンスを指すように変数を何らかの形で混同していると想定して進めています。

この行が原因です:

forum.topic_count = topic.objects.filter(forum = forum).count()
#                   ^^^^^

あなたは使用する必要があります:

forum.topic_count = Topic.objects.filter(forum = forum).count()
#                   ^^^^^
#                   Model, not instance.

何が問題なのですか?objectsあるManagerクラスレベルではなく、インスタンスが利用できます。詳細については、オブジェクトの取得に関するドキュメントを参照してください。見積もり:

Managers「テーブルレベル」操作と「レコードレベル」操作を強制的に分離するために、モデルインスタンスからではなく、モデルクラスを介してのみアクセスできます。

(強調を追加)

更新

以下の@Danielからのコメントを参照してください。クラス名にタイトルケースを使用することをお勧めします(いや、あなたは:Pでなければなりません)。たとえば、のTopic代わりにtopic。クラス名は、インスタンスを参照しているのかクラスを参照しているのかにかかわらず、混乱を引き起こします。Manager isn't accessible via <model> instances非常に具体的であるため、私は解決策を提供することができます。エラーは必ずしも自明ではないかもしれません。


ただし、topic実際のモデルクラスであり、彼が提供したコードによるとインスタンスではないようです。
ダニエルディパオロ2010年

@ダニエル:本当。それでも、このエラーManager isn't accessible via Foo instancesManager、インスタンスを使用してアクセスしようとした場合にのみ発生する可能性があります。ソースコードを参照してください:code.djangoproject.com/svn/django/trunk/django/db/models/…–
Manoj Govindan

4
実際、クラス名に小文字を使用しない別の理由(「ベストプラクティス」以外):)topicローカルインスタンス変数として使用している可能性があり、クラスへの参照を吹き飛ばしているように見えます。
ダニエルディパオロ2010年

2
使用すべきだったtopic.model_class().objects
Nimo 2013年

7
を使用することもできますtopic.__class__.objectsmodel_class()上記の@Nimoで言及されているように機能しないようです
sleepycal 2014年

53
topic.__class__.objects.get(id=topic_id)

Djangov1.10以降で動作します。
ジェームズ

3
これは、__class__私たちが子孫クラスの実際の名前がわからないよう、同様に抽象モデル内のメソッドのために良い作品。この状況では、私は使用しましたself.__class__.objects.get
Cometsong 2018年

33

django <1.10の場合

topic._default_manager.get(id=topic_id)

このように使うべきではありませんが。_default_managerと_base_managerはプライベートであるため、独自の関数でManagerを使用する場合など、トピックモデル内にいる場合にのみ使用することをお勧めします。

class Topic(Model):
.
.
.
    def related(self)
        "Returns the topics with similar starting names"
        return self._default_manager.filter(name__startswith=self.name)

topic.related() #topic 'Milan wins' is related to:
# ['Milan wins','Milan wins championship', 'Milan wins by one goal', ...]

5
おかげで、この答えはまさに私が探していたものでした。何度も投票できたらいいのにと思います。これの私のユースケースは、抽象モデルに機能を追加する場合であり、最終的なモデルクラスが何と呼ばれるかが(このレベルでは)わかりません。
fadedbee 2012年

2
またはを使用しますtopic.__class__.objects.get(id=topic_id)
Bentley4 2013年

1
これは古い答えですが、Django v1.10以降、これらのプライベートメソッドは表示されなくなりました。しかし、self.__class__.objectsあなたの他の答えごとにトリックを行います。
ジェームズ

5

一対の括弧が原因である可能性もあります。

ModelClass().objects.filter(...)

正しい代わりに

ModelClass.objects.filter(...)

bpython(またはIDE)が自動的に括弧を追加するときに時々私に起こります。

もちろん、結果は同じです。クラスの代わりにインスタンスがあります。


0

トピックがContentTypeインスタンス(そうではない)の場合、これは機能します。

topic.model_class().objects.filter(forum = forum)

model_class()ContentTypeモデルのメソッドです。を含む他のモデルインスタンスにtopicmodel_classメソッドがありません。
Alasdair 2013年

すみません、質問を読み間違えたに違いありません。私は...一見、類似した問題を解決しようとしていた
ニモ

0

このエラーに似た問題が発生しました。そして、あなたのコードを振り返ると、それもあなたの問題である可能性があるようです。あなたの問題は、「id」を「int(topic_id)」と比較し、topic_idが設定されていないことだと思います。

def test(request, post_id):
    post = topic.objects.get(id = int(topic_id))
    post.delete()

あなたのコードは「topic_id」ではなく「post_id」を使うべきだと思います

def test(request, post_id):
    post = topic.objects.get(id = int(post_id))
    post.delete()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.