Menedżer nie jest dostępny za pośrednictwem instancji modelu

87

Próbuję pobrać instancję obiektów modelu w innej i zgłaszam ten błąd:

 Manager isn't accessible via topic instance

Oto mój model:

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

Oto mój pogląd:

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

I otrzymuję:

post.delete()
forum.topic_count = topic.objects.filter(forum = forum).count()
Manager isn't accessible via topic instances
ThomasDurin
źródło

Odpowiedzi:

126

Omawiany błąd jest spowodowany próbą uzyskania dostępu do Managermodelu za pośrednictwem instancji modelu. Użyłeś dolne liter nazwy klas. To sprawia, że ​​trudno powiedzieć, czy błąd jest spowodowany przez instancję uzyskującą dostęp do pliku, Managerczy nie. Ponieważ inne scenariusze, które mogą powodować ten błąd, są nieznane, wychodzę z założenia, że ​​w jakiś sposób pomieszałeś topiczmienną, tak że w końcu wskażesz wystąpienie topicmodelu zamiast klasy.

Ta linia jest winowajcą:

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

Musisz użyć:

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

Co się dzieje? objectsjest Managerdostępny na poziomie klasy, a nie dla instancji. Szczegółowe informacje można znaleźć w dokumentacji dotyczącej pobierania obiektów . Wycena pieniędzy:

Managerssą dostępne tylko za pośrednictwem klas modelu, a nie z instancji modelu, aby wymusić oddzielenie operacji „na poziomie tabeli” od operacji „na poziomie rekordu”.

(Podkreślenie dodane)

Aktualizacja

Zobacz komentarze @Daniel poniżej. Dobrym pomysłem jest (nie, MUSISZ: P) używać wielkich liter w nazwach klas. Na przykład Topiczamiast topic. Nazwy twoich klas powodują pewne zamieszanie, niezależnie od tego, czy odnosisz się do instancji, czy do klasy. Ponieważ Manager isn't accessible via <model> instancesjest bardzo specyficzny, jestem w stanie zaoferować rozwiązanie, błąd może nie zawsze być tak oczywisty.

Manoj Govindan
źródło
Jednak topicwydaje się, że jest to rzeczywista klasa modelu, a nie instancja zgodnie z dostarczonym przez niego kodem.
Daniel DiPaolo,
@Daniel: prawda. A jednak błąd Manager isn't accessible via Foo instancesjest możliwy tylko wtedy, gdy próbujesz uzyskać dostęp do Managerza pomocą instancji. Zobacz kod źródłowy: code.djangoproject.com/svn/django/trunk/django/db/models/…
Manoj Govindan
4
Rzeczywiście, być może jest to inny powód (inny niż „to najlepsza praktyka”), aby nie używać małych liter w nazwach klas :) Wydawałoby się, że potencjalnie używa topicjako zmiennej lokalnej instancji i usuwa odwołanie do klasy.
Daniel DiPaolo
2
Powinieneś był użyćtopic.model_class().objects
Nimo
7
Możesz również użyć topic.__class__.objects. Wydaje się, że model_class()wspomniane przez @Nimo powyżej nie działa
senny
54
topic.__class__.objects.get(id=topic_id)
mihaicc
źródło
Działa od Django v1.10.
James,
3
To __class__działa lepiej dla metod w abstrakcyjnych modeli, jak również, gdy nie znamy rzeczywistej nazwy potomkiem klasy. W tej sytuacji użyłemself.__class__.objects.get
Cometsong
33

Dla django <1.10

topic._default_manager.get(id=topic_id)

Chociaż nie powinieneś tego używać w ten sposób. _Default_manager i _base_manager są prywatne, więc zaleca się ich używanie tylko wtedy, gdy jesteś w modelu tematu, na przykład gdy chcesz użyć menedżera w zastrzeżonej funkcji, powiedzmy:

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
źródło
5
Dzięki, ta odpowiedź była właśnie tym, czego szukałem. Chciałbym móc głosować więcej niż raz. Mój przypadek użycia to dodawanie funkcjonalności do modelu abstrakcyjnego, gdzie nie będziesz wiedział (na tym poziomie), jak nazywa się ostateczna klasa modelu.
fadedbee
2
Lub użyj topic.__class__.objects.get(id=topic_id).
Bentley4
1
To stara odpowiedź, ale od wersji 1.10 Django nie widzę już tych prywatnych metod. Jednak self.__class__.objectsdziała sztuczka według innej odpowiedzi.
James,
5

Może być również spowodowane zbyt dużą parą parantez, np

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

zamiast prawidłowego

ModelClass.objects.filter(...)

Zdarza mi się czasami, gdy bpython (lub IDE) automatycznie dodaje paranthezy.

Wynik jest oczywiście taki sam - zamiast klasy masz instancję.

Markus
źródło
0

gdyby topic był instancją ContentType (a nią nie jest), zadziałałoby:

topic.model_class().objects.filter(forum = forum)
Nimo
źródło
model_class()jest metodą ContentTypemodelu. Inne instancje modelu, w tym topic, nie mają model_classmetody.
Alasdair
Przepraszam, chyba źle odczytałem pytanie. Próbowałem rozwiązać pozornie podobne pytanie ...
Nimo
0

Właśnie miałem problem podobny do tego błędu. Patrząc wstecz na twój kod, wydaje się, że może to być również twój problem. Myślę, że Twoim problemem jest to, że nie ustawiono porównania „id” z „int (topic_id)” i topic_id.

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

Zgaduję, że Twój kod powinien zawierać „post_id”, a nie „topic_id”

def test(request, post_id):
    post = topic.objects.get(id = int(post_id))
    post.delete()
brianwaganer
źródło