3

django核心代码片段:

class ForeignKey(RelatedField, Field):

    ...

    def db_type(self, connection):
        rel_field = self.rel.get_related_field()
        if (isinstance(rel_field, AutoField) or
                (not connection.features.related_fields_match_type and
                isinstance(rel_field, (PositiveIntegerField,
                                       PositiveSmallIntegerField)))):
            return IntegerField().db_type(connection=connection)
        return rel_field.db_type(connection=connection)

这段代码非常糟糕,因为如果我定义一个继承自的自定义字段AutoField,那么我的 db_type 方法将被忽略。

我想做的是隐藏我的类是AutoField. 在 C++ 中,我会通过私有继承来做到这一点。

有没有办法欺骗isinstance返回False或隐藏继承?

我的自定义字段的代码:

class MyAutoField(models.AutoField):

    def __init__(self, length, *args, **kwargs):
        self.length = length
        super(MyAutoField, self).__init__(*args, **kwargs)

    def db_type(self, connection):
        if connection.vendor == 'oracle':
            return 'NUMBER(%s,0)' % (self.length)
        if connection.vendor == 'postgresql':
            if self.length <= 4:
                return 'smallint'
            if self.length <= 9:
                return 'integer'
            return 'bigint'
        return super(MyAutoField, self).db_type(connection)
4

1 回答 1

6

So I have a way to do it, but its via "monkey patching." You can't use ABCMeta because that requires you override your base class's metaclass.

You could "change" isinstance as follows. It is important that "patches" only gets imported once, and I would only do this if is no other way.

patches.py

import django.models
import mymodel
import __builtin__
def _isinstance(instance, clz):
    if clz is models.AutoField and isinstance_orig(instance, MyAutoField):
        return False
    return isinstance_orig(instance, clz)
__builtin__.isinstance_orig = __builtin__.isinstance
__builtin__.isinstance = _isinstance

Then your test program:

class MyAutoField(models.AutoField): pass

x = MyAutoField()
print(isinstance(x, models.AutoField))
print(isinstance(x, models.MyAutoField))

Introducing Abstract Base Classes: PEP-3119 . Below is an abstract example...

class ABCMeta(type):

  def __instancecheck__(cls, inst):
    """Implement isinstance(inst, cls)."""
    return any(cls.__subclasscheck__(c)
               for c in {type(inst), inst.__class__})

  def __subclasscheck__(cls, sub):
    """Implement issubclass(sub, cls)."""
    candidates = cls.__dict__.get("__subclass__", set()) | {cls}
    return any(c in candidates for c in sub.mro())
于 2013-01-28T16:57:36.920 回答