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

だから私にはそれを行う方法がありますが、それは「モンキーパッチ」によるものです。ABCMeta基本クラスのメタクラスをオーバーライドする必要があるため、 使用できません。

次のように isinstance を「変更」できます。「パッチ」は一度だけインポートすることが重要であり、他に方法がない場合にのみこれを行います。

パッチ.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

次に、テスト プログラム:

class MyAutoField(models.AutoField): pass

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

抽象基本クラスの紹介: PEP-3119 . 以下は抽象的な例です...

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 に答える