web-dev-qa-db-fra.com

Le gestionnaire n'est pas accessible via les instances de modèle

j'essaie d'obtenir une instance d'objets de modèle dans une autre. Et je soulève cette erreur:

 Manager isn't accessible via topic instance

Voici mon modèle:

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()

Voici mon point de vue:

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

Et je reçois:

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

L'erreur en question est provoquée lorsque vous essayez d'accéder à la Manager d'un modèle via une instance du modèle. Vous avez utilisé noms de classe en minuscule. Cela rend difficile de dire si l'erreur est provoquée par une instance accédant à la variable Manager ou non. Etant donné que les autres scénarios pouvant causer cette erreur sont inconnus, je pars du principe que vous avez mélangé la variable topic de sorte que vous finissiez par pointer vers une instance du modèle topic au lieu de la classe. 

Cette ligne est le coupable: 

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

Vous devez utiliser:

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

Qu'est-ce qui ne va pas? objects est une Manager disponible au niveau de la classe, pas pour les instances. Consultez la documentation relative à la récupération d'objets pour plus de détails. Devis d'argent:

Managers sont accessibles uniquement via les classes de modèle, et non à partir d'instances de modèle, pour imposer une séparation entre les opérations "au niveau de la table" et les opérations au niveau de l'enregistrement.

(Soulignement ajouté)

Mettre à jour

Voir les commentaires de @Daniel ci-dessous. C'est une bonne idée (non, vous DEVEZ: P) d'utiliser la casse de titre pour les noms de classe. Par exemple, Topic au lieu de topic. Vos noms de classe créent une certaine confusion, que vous parliez d'une instance ou d'une classe. Étant donné que le Manager isn't accessible via <model> instances est très spécifique, je suis en mesure de proposer une solution. L’erreur peut ne pas toujours être aussi évidente. 

96
Manoj Govindan
topic.__class__.objects.get(id=topic_id)
39
mihaicc

Pour Django <1.10

topic._default_manager.get(id=topic_id)

Bien que vous ne devriez pas l'utiliser comme ça. _Default_manager et _base_manager sont privés. Il est donc recommandé de les utiliser uniquement si vous vous trouvez dans le modèle Topic, comme lorsque vous souhaitez utiliser le gestionnaire dans une fonction propriétaire, par exemple:

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', ...]
31
mihaicc

Peut aussi être causé par une paire de parenthèses trop lourde, par ex.

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

au lieu du correct

ModelClass.objects.filter(...)

Cela m’arrive parfois lorsque bpython (ou un IDE) ajoute automatiquement des parenthèses.

Bien entendu, le résultat est identique: vous avez une instance au lieu d'une classe.

3
Markus

si topic était une instance de ContentType (ce qui n'est pas le cas), cela aurait fonctionné:

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

Je viens d'avoir un problème similaire à cette erreur. Et en regardant votre code, il semble que cela pourrait également être votre problème. Je pense que votre problème est que vous comparez "id" à "int (topic_id)" et topic_id n'est pas défini.

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

Je suppose que votre code devrait utiliser "post_id" et non "topic_id"

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