No se puede acceder al administrador a través de instancias de modelo

84

Estoy tratando de obtener una instancia de objetos modelo en otra y aparezco este error:

 Manager isn't accessible via topic instance

Aquí está mi modelo:

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

Esta es mi opinión:

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

Y obtengo:

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

Respuestas:

123

El error en cuestión se produce cuando intenta acceder al Managerde un modelo a través de una instancia del modelo. Ha utilizado nombres de clases en minúsculas . Esto hace que sea difícil decir si el error es causado por una instancia que accede Managero no. Dado que se desconocen otros escenarios que pueden causar este error, procedo asumiendo que de alguna manera ha mezclado la topicvariable para que termine apuntando a una instancia del topicmodelo en lugar de la clase.

Esta línea es la culpable:

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

Tienes que usar:

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

¿Qué va mal? objectsestá Managerdisponible a nivel de clase, no para las instancias. Consulte la documentación para recuperar objetos para obtener más detalles. Cotización de dinero:

Managersson accesibles solo a través de clases de modelo, en lugar de instancias de modelo, para imponer una separación entre las operaciones de "nivel de tabla" y las operaciones de "nivel de registro".

(Énfasis añadido)

Actualizar

Vea los comentarios de @Daniel a continuación. Es una buena idea (no, DEBE: P) usar mayúsculas y minúsculas para los nombres de las clases. Por ejemplo, en Topiclugar de topic. Los nombres de sus clases causan cierta confusión ya sea que se refiera a una instancia o una clase. Dado que el Manager isn't accessible via <model> instanceses muy específico, puedo ofrecer una solución. El error puede no ser tan evidente siempre.

Manoj Govindan
fuente
Sin embargo, topicparece ser la clase de modelo real, y no una instancia según el código que proporcionó.
Daniel DiPaolo
@Daniel: cierto. Y, sin embargo, el error Manager isn't accessible via Foo instancessolo es posible cuando intentas acceder a Manageruna instancia. Vea el código fuente: code.djangoproject.com/svn/django/trunk/django/db/models/…
Manoj Govindan
4
De hecho, quizás otra razón (además de "es la mejor práctica") para no usar letras minúsculas para los nombres de las clases :) Parece que está usando potencialmente topiccomo una variable de instancia local y eliminando la referencia a la clase.
Daniel DiPaolo
2
Deberías haber usadotopic.model_class().objects
Nimo
7
También puede utilizar topic.__class__.objects. Parece que lo model_class()mencionado por @Nimo arriba no funciona
sleepycal
53
topic.__class__.objects.get(id=topic_id)
mihaicc
fuente
Funciona a partir de Django v1.10.
James
3
Esto también __class__funciona mejor para métodos dentro de modelos abstractos, ya que no conocemos el nombre real de la clase descendiente. En esta situación, he usadoself.__class__.objects.get
Cometsong
33

Para django <1.10

topic._default_manager.get(id=topic_id)

Aunque no deberías usarlo así. El _default_manager y _base_manager son privados, por lo que se recomienda usarlos solo si está dentro del modelo Topic, como cuando desea usar el Administrador en una función propietaria, digamos:

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', ...]
mihaicc
fuente
5
Gracias, esta respuesta era justo lo que estaba buscando. Ojalá pudiera votar a favor más de una vez. Mi caso de uso para esto es cuando está agregando funcionalidad a un modelo abstracto, donde no sabrá (en este nivel) cómo se llama la clase de modelo final.
fadedbee
2
O usar topic.__class__.objects.get(id=topic_id).
Bentley4
1
Esta es una respuesta antigua, pero a partir de Django v1.10 ya no veo estos métodos privados. Sin embargo, self.__class__.objectsfunciona el truco según tu otra respuesta.
James
5

También podría ser causado por un par de paréntesis demasiado, p. Ej.

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

en lugar de la correcta

ModelClass.objects.filter(...)

A veces me pasa cuando bpython (o un IDE) agrega automáticamente paréntesis.

El resultado, por supuesto, es el mismo: tiene una instancia en lugar de una clase.

Markus
fuente
0

si el tema fuera una instancia de ContentType (que no lo es), esto habría funcionado:

topic.model_class().objects.filter(forum = forum)
Nimo
fuente
model_class()es un método del ContentTypemodelo. Otras instancias de modelo, incluidas topic, no tienen un model_classmétodo.
Alasdair
Lo siento, debo haber leído mal la pregunta. Estaba tratando de resolver una pregunta aparentemente similar ...
Nimo
0

Acabo de tener un problema similar a este error. Y mirando hacia atrás en su código, parece que también podría ser su problema. Creo que su problema es que su comparación de "id" con "int (topic_id)" y topic_id no está establecida.

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

Supongo que su código debería usar "post_id" no "topic_id"

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