15

Tôi đã tạo một lớp phân lớp ListView và hai mixin tùy chỉnh đã triển khai hàm get_context_data. Tôi muốn ghi đè lên chức năng này vào các lớp con:Python đa chức năng thừa kế ghi đè và ListView trong django

from django.views.generic import ListView 

class ListSortedMixin(object): 
    def get_context_data(self, **kwargs): 
     print 'ListSortedMixin' 
     return kwargs 

class ListPaginatedMixin(object): 
    def get_context_data(self, **kwargs): 
     print 'ListPaginatedMixin' 
     return kwargs 

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView): 
    def get_context_data(self, **context): 
    super(ListSortedMixin,self).get_context_data(**context) 
    super(ListPaginatedMixin,self).get_context_data(**context) 
    return context 

Khi tôi thực hiện MyListView nó chỉ in "ListSortedMixin". Vì một số lý do, python đang thực hiện ListSortedMixin.get_context_data thay cho MyListView.get_context_data. Tại sao?

Nếu tôi thay đổi thứ tự kế thừa thành ListPaginatedMixin, ListSortedMixin, ListView, ListPaginatedMixin.get_context_data được thực hiện.

Tôi có thể ghi đè hàm get_context_data như thế nào?

Trả lời

16

Đây là câu hỏi cũ nhưng tôi tin câu trả lời là không chính xác. Có lỗi trong mã của bạn.Nó nên đọc:

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView): 
    def get_context_data(self, **context): 
     super(MyListView,self).get_context_data(**context) 
     return context 

Thứ tự mà các get_context_data sẽ được gọi theo thứ tự như quy định tại tờ khai của MyListView. Lưu ý rằng đối số của siêu là MyListView và không phải là các lớp siêu.

CẬP NHẬT:

tôi bị mất rằng mixins của bạn không gọi siêu. Họ nên. Vâng, ngay cả khi họ kế thừa từ đối tượng, bởi vì siêu gọi phương thức tiếp theo trong MRO, không nhất thiết phụ huynh của lớp đó là trong

from django.views.generic import ListView 

class ListSortedMixin(object): 
    def get_context_data(self, **kwargs): 
     print 'ListSortedMixin' 
     return super(ListSortedMixin,self).get_context_data(**context) 

class ListPaginatedMixin(object): 
    def get_context_data(self, **kwargs): 
     print 'ListPaginatedMixin' 
     return super(ListPaginatedMixin,self).get_context_data(**context) 

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView): 
    def get_context_data(self, **context): 
     return super(MyListView,self).get_context_data(**context) 

Đối MyListView các MRO là sau đó:.

  1. MyListView
  2. ListSortedMixin
  3. ListPaginatedMixin
  4. ListView
  5. Dù là trên ListView ... n. đối tượng

Gọi từng cái một có thể hoạt động, nhưng không phải là cách nó được dự định sử dụng.

CẬP NHẬT 2

Sao chép và dán ví dụ để chứng minh quan điểm của tôi.

class Parent(object): 
    def get_context_data(self, **kwargs): 
     print 'Parent' 

class ListSortedMixin(object): 
    def get_context_data(self, **kwargs): 
     print 'ListSortedMixin' 
     return super(ListSortedMixin,self).get_context_data(**kwargs) 

class ListPaginatedMixin(object): 
    def get_context_data(self, **kwargs): 
     print 'ListPaginatedMixin' 
     return super(ListPaginatedMixin,self).get_context_data(**kwargs) 

class MyListView(ListSortedMixin, ListPaginatedMixin, Parent): 
    def get_context_data(self, **kwargs): 
     return super(MyListView,self).get_context_data(**kwargs) 


m = MyListView() 
m.get_context_data(l='l') 
+0

Trong trường hợp này 'super (MyListView, self) .get_context_data (** context)' giống như 'ListSortedMixin.get_context_data (self, ** context)'. Tôi nghĩ rằng [câu trả lời trước] (http://stackoverflow.com/a/9939867/959819) là chính xác: tôi cần phải gọi từng chức năng của cha mẹ. –

+0

Vấn đề là mixins của bạn không gọi siêu. Ngay cả khi mixin kế thừa từ 'object' thì chúng sẽ gọi super. Đại biểu đại diện cho đối tượng tiếp theo trong MRO (thứ tự độ phân giải phương thức), phụ thuộc vào thứ tự mà chúng được chỉ định trong khai báo MyListView. Tôi sẽ cập nhật câu trả lời của tôi ở trên để làm cho nó rõ ràng hơn. –

+0

Chính xác. Do đó phương thức được gọi trong ví dụ của bạn chỉ là 'ListSortedMixin'. Tôi cần phải gọi thủ công tất cả các chức năng của cha mẹ. –

10

Nếu những gì bạn đang cố gắng làm là gọi các phương thức ghi đè theo thứ tự cố định. Sử dụng cú pháp này:

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView): 
    def get_context_data(self, **context): 
    ListSortedMixin.get_context_data(self, **context) 
    ListPaginatedMixin.get_context_data(self, **context) 
    return context 

Siêu sẽ không hoạt động trong trường hợp này. Xem hướng dẫn cho super(type[, object]):

Return một đối tượng proxy rằng phương pháp đại biểu các cuộc gọi đến cha mẹ hoặc anh chị em ruột của lớp loại. Điều này rất hữu ích cho việc truy cập các phương thức kế thừa đã được ghi đè trong một lớp. Thứ tự tìm kiếm giống với thứ tự được sử dụng bởi getattr() ngoại trừ loại chính nó bị bỏ qua.

Có hai trường hợp sử dụng điển hình cho siêu. Trong một hệ thống phân cấp lớp với thừa kế đơn, siêu có thể được sử dụng để tham chiếu đến các lớp cha mà không đặt tên chúng một cách rõ ràng, do đó làm cho mã nhiều hơn có thể duy trì. Việc sử dụng này song song với việc sử dụng siêu ngôn ngữ khác trong các ngôn ngữ lập trình khác.

Trường hợp sử dụng thứ hai là hỗ trợ hợp tác đa thừa kế trong môi trường thực thi động. Trường hợp sử dụng này là duy nhất đối với Python và không được tìm thấy trong các ngôn ngữ hoặc ngôn ngữ được biên dịch tĩnh mà chỉ hỗ trợ kế thừa đơn. Điều này làm cho nó có thể thực hiện “sơ đồ kim cương” trong đó nhiều lớp cơ sở thực hiện cùng phương thức . Thiết kế tốt chỉ ra rằng phương thức này có cùng ký tự số trong mọi trường hợp (vì thứ tự cuộc gọi được xác định ở thời gian chạy là , vì thứ tự đó thích nghi với các thay đổi trong phân cấp lớp, và vì thứ tự đó có thể bao gồm các lớp anh chị em chưa biết trước khi chạy).

Vì vậy, đối số của siêu là lớp có cha mẹ hoặc anh chị em lớp proxy bạn muốn nhận. super(ListSortedMixin,self).get_context_data(**context) sẽ không nhất thiết phải gọi get_context_data trong số ListSortedMixin. Tùy thuộc vào thứ tự giải quyết phương thức (MRO) mà bạn có thể nhận được bằng cách sử dụng print MyListView.__mro__

Vì vậy, super() sẽ gọi get_context_data của cha mẹ hoặc anh chị em. Thứ tự thực hiện thích nghi với những thay đổi trong hệ thống phân cấp lớp và vì thứ tự đó có thể bao gồm các lớp anh chị em chưa biết trước khi chạy.

+0

Cảm ơn bạn đã phản hồi nhanh! Lời giải thích tốt đẹp, tôi hiểu nó ngay bây giờ :) –

Các vấn đề liên quan