Đối với tình yêu của Chúa Kitô không sử dụng monkeypatching cho việc này. Sử dụng thừa kế, đó là những gì nó cho.
Chỉ cần có các plugin cần làm việc với nhiều trường mở rộng mô hình hiện có và sau đó sử dụng một trong nhiều kỹ thuật để có được cá thể lớp chuyên biệt nhất của mô hình. Tôi sử dụng các lớp dưới đây như một mixin trên tất cả các lớp học sẽ được sử dụng theo cách này, để đạt được điều này.
class Specializable(object):
@classmethod
def all_classes(selfclass):
""" Returns the class this is called on, plus its known subclasses """
subs = selfclass.__subclasses__()
subs.insert(0, selfclass)
return subs
def get_sub_instance(self):
""" Gets concrete instance of object of deepest subtype which has its ancestor link pointing to this object (depth first search behaviour). """
selftype = type(self)
for klass in selftype.__subclasses__():
this_ptr_name = klass._meta.get_ancestor_link(selftype).name
try:
sub = klass.objects.get(**{this_ptr_name: self})
subsub = sub.get_sub_instance()
if subsub: return subsub
else: return sub
except ObjectDoesNotExist:
pass
@classmethod
def new_with_translator(selfclazz, name):
def new(cls, *args, **kwargs):
selfclazz.create_subclass_translator(cls, install = name)
return models.Model.__new__(cls, *args, **kwargs)
return new
@classmethod
def create_subclass_translator(selfclazz, Baseclass, install=None):
""" Creates a classmethod object for installation on Baseclass,
which acts as a factory for instances of subclasses of Baseclass,
when called on that subclass. The factory takes as input an instance
of a subclass (old_instance), and a dictionary of properties with which
to initialise the new instance. It also installs the base class instance
of old_instance as the base instance for the new instance. All three will
share the same pk.
if install is set, this will also install the function on Baseclass under
that name if it does not have a property of that name. """
def create_from_other_instance(selfclass, old_instance, properties):
""" Creates an instance of this class using properties and old_instance.
In particular, it will try to re-use the superclass instance of old_instance.
properties should contain all of the fields for this class (but need not include the superclass values)
This *must* be called on a subclass of the baseclass - it will give odd results if called on the baseclass itself.
This will NOT delete old_instance and it will NOT SAVE the object created - the caller is responsible for
those things."""
if selfclass is Baseclass: raise TypeError("This method cannot be used on the base class")
ancestor_link = selfclass._meta.get_ancestor_link(Baseclass).name
properties.update({ancestor_link: getattr(old_instance,ancestor_link)})
for f in get_model_fields(Baseclass):
val = getattr(old_instance, f)
if val and not properties.get(f):
properties[f] = val
return selfclass(**properties)
new_method = classmethod(create_from_other_instance)
if install and not hasattr(Baseclass, install):
setattr(Baseclass, install, new_method)
return new_method
Dưới đây là một ví dụ về việc sử dụng nó, từ một số mã của tôi:
#KYCable inherits from Model, so must precede Model
class Director(KYCable, models.Model, Specializable, DateFormatter, AdminURL, Supercedable):
def get_individual(self):
return self.get_sub_instance().get_individual()
Như bạn thấy, Specializable
lớp cần phải lưu ý rằng phương pháp của họ có thể bị ghi đè bởi lớp con, và được mã hóa thích hợp.
Nếu plugin của bạn biết về mối quan hệ lớp con, thì nó có thể sử dụng các thủ thuật như tìm kiếm trên cùng một id mô hình trong các lớp con mà nó biết, để có được cá thể mô hình phân lớp tương ứng khi được trình bày với một cá thể siêu lớp.
bảng Thay đổi cấu trúc qua monkeypatch là IMHO một ý tưởng rất rất xấu. Bạn có thể muốn sử dụng GenericForeignKeys hoặc bất kỳ giải pháp "không phá hủy" đặc biệt khác thay thế. –
Đó là hiệu quả hơn, không phải là xấu xí, và tôi là nhà phát triển của tất cả những ứng dụng (vì vậy không có rủi ro của xung đột không giám sát). Ngay cả khi tôi chưa bao giờ sử dụng GenericForeignKeys nhưng tôi không thích chúng. – christophe31
Tôi không hiểu vấn đề. Một bản vá khỉ thích hợp sẽ làm cho nó không đáng kể từ phía nam. Bạn chỉ cần thêm tập lệnh di chuyển đệ quy. – deufeufeu