Người quản lý không thể truy cập thông qua các phiên bản mô hình


83

Tôi đang cố lấy ví dụ đối tượng mô hình trong một đối tượng khác và tôi phát sinh lỗi này:

 Manager isn't accessible via topic instance

Đây là mô hình của tôi:

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

Đây là quan điểm của tôi:

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

Va tôi lây :

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

Câu trả lời:


122

Lỗi được đề cập được gây ra khi bạn cố gắng truy cập Managermô hình thông qua một phiên bản của mô hình. Bạn đã sử dụng chữ thường tên lớp. Điều này làm cho rất khó để nói liệu lỗi có phải do một phiên bản đang truy cập vào Managerhay không. Vì các tình huống khác có thể gây ra lỗi này là không xác định nên tôi đang tiếp tục giả định rằng bằng cách nào đó bạn đã trộn topicbiến bằng cách nào đó để cuối cùng bạn trỏ đến một thể hiện của topicmô hình thay vì lớp.

Dòng này là thủ phạm:

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

Bạn phải sử dụng:

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

Có chuyện gì vậy? objectslà một Managerkhả dụng ở cấp lớp, không phải đối với các phiên bản. Xem tài liệu để lấy các đối tượng để biết chi tiết. Báo giá tiền:

Managerschỉ có thể truy cập thông qua các lớp mô hình, thay vì từ các cá thể mô hình, để thực thi sự tách biệt giữa các hoạt động "cấp bảng" và các hoạt động "cấp bản ghi".

(Đã nhấn mạnh thêm)

Cập nhật

Xem các bình luận từ @Daniel bên dưới. Đó là một ý kiến ​​hay (nay, bạn PHẢI: P) để sử dụng tiêu đề cho tên lớp. Ví dụ Topicthay vì topic. Tên lớp của bạn gây ra một số nhầm lẫn cho dù bạn đang tham chiếu đến một cá thể hay một lớp. Vì vấn đề Manager isn't accessible via <model> instancesrất cụ thể nên tôi có thể đưa ra giải pháp, lỗi có thể không quá rõ ràng.


Tuy nhiên, topicdường như là lớp mô hình thực tế, và không phải là một cá thể theo mã mà anh ta cung cấp.
Daniel DiPaolo

@Daniel: đúng. Tuy nhiên, lỗi Manager isn't accessible via Foo instanceschỉ có thể xảy ra khi bạn cố gắng truy cập một phiên bản Managerbằng cách sử dụng. Xem mã nguồn: code.djangoproject.com/svn/django/trunk/django/db/models/…
Manoj Govindan

4
Thật vậy, có lẽ một lý do khác (ngoài "đó là phương pháp hay nhất") để không sử dụng các chữ cái viết thường cho tên lớp :) Có vẻ như anh ta có khả năng sử dụng topicnhư một biến cá thể cục bộ và thổi bay tham chiếu đến lớp.
Daniel DiPaolo

2
Bạn nên sử dụng topic.model_class().objects
Nimo

7
Bạn cũng có thể sử dụng topic.__class__.objects. Có vẻ như nó model_class()được @Nimo đề cập ở trên không hoạt động
sleepycal

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

Hoạt động như Django v1.10.
James

3
Điều này cũng __class__hoạt động tốt hơn đối với các phương thức trong mô hình trừu tượng, vì chúng ta không biết tên thực của lớp con cháu. Trong tình huống này, tôi sử dụngself.__class__.objects.get
Cometsong

33

Đối với django <1.10

topic._default_manager.get(id=topic_id)

Mặc dù bạn không nên sử dụng nó như thế này. _Default_manager và _base_manager là riêng tư, vì vậy bạn chỉ nên sử dụng chúng nếu bạn đang ở trong mô hình Chủ đề, như khi bạn muốn sử dụng Trình quản lý trong một hàm độc quyền, hãy nói:

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
Cảm ơn, câu trả lời này chính là những gì tôi đang tìm kiếm. Tôi ước tôi có thể bỏ phiếu nhiều hơn một lần. Trường hợp sử dụng của tôi cho việc này là khi bạn thêm chức năng vào một mô hình trừu tượng, nơi bạn sẽ không biết (ở cấp độ này) lớp mô hình cuối cùng được gọi là gì.
fadebee

2
Hoặc sử dụng topic.__class__.objects.get(id=topic_id).
Bentley 4

1
Đây là một câu trả lời cũ, nhưng kể từ Django v1.10, tôi không thấy các phương thức riêng tư này nữa. Tuy nhiên, self.__class__.objectscó lừa cho câu trả lời khác của bạn.
James

5

Cũng có thể được gây ra bởi một cặp câu lệnh quá nhiều, ví dụ:

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

thay vì đúng

ModelClass.objects.filter(...)

Đôi khi xảy ra với tôi khi bpython (hoặc một IDE) tự động thêm các tham số.

Tất nhiên, kết quả là như nhau - bạn có một cá thể thay vì một lớp.


0

nếu chủ đề là một phiên bản ContentType (mà không phải), thì điều này sẽ hoạt động:

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

model_class()là một phương thức của ContentTypemô hình. Các trường hợp mô hình khác, bao gồm topic, không có model_classphương pháp.
Alasdair

Xin lỗi, tôi phải đọc sai câu hỏi. Tôi đã cố gắng để giải quyết một câu hỏi dường như-tương tự ...
Nimo

0

Tôi vừa gặp sự cố tương tự như lỗi này. Và nhìn lại mã của bạn, có vẻ như đó cũng có thể là vấn đề của bạn. Tôi nghĩ rằng vấn đề của bạn là so sánh "id" với "int (topic_id)" và topic_id của bạn không được đặt.

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

Tôi đoán mã của bạn nên sử dụng "post_id" chứ không phải "topic_id"

def test(request, post_id):
    post = topic.objects.get(id = int(post_id))
    post.delete()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.