Das Deskriptor-Protokoll funktioniert gut, aber ich habe immer noch ein Problem, das ich gerne lösen würde.Wie kann ich den Attributnamen erhalten, wenn ich in Python mit dem Deskriptorprotokoll arbeite?
Ich habe einen Descriptor:
class Field(object):
def __init__(self, type_, name, value=None, required=False):
self.type = type_
self.name = "_" + name
self.required = required
self._value = value
def __get__(self, instance, owner):
return getattr(instance, self.name, self.value)
def __set__(self, instance, value):
if value:
self._check(value)
setattr(instance, self.name, value)
else:
setattr(instance, self.name, None)
def __delete__(self, instance):
raise AttributeError("Can't delete attribute")
@property
def value(self):
return self._value
@value.setter
def value(self, value):
self._value = value if value else self.type()
@property
def _types(self):
raise NotImplementedError
def _check(self, value):
if not isinstance(value, tuple(self._types)):
raise TypeError("This is bad")
Diese subclassed ist:
class CharField(Field):
def __init__(self, name, value=None, min_length=0, max_length=0, strip=False):
super(CharField, self).__init__(unicode, name, value=value)
self.min_length = min_length
self.max_length = max_length
self.strip = strip
@property
def _types(self):
return [unicode, str]
def __set__(self, instance, value):
if self.strip:
value = value.strip()
super(CharField, self).__set__(instance, value)
Und dann verwendet, ist eine Modellklasse:
class Country(BaseModel):
name = CharField("name")
country_code_2 = CharField("country_code_2", min_length=2, max_length=2)
country_code_3 = CharField("country_code_3", min_length=3, max_length=3)
def __init__(self, name, country_code_2, country_code_3):
self.name = name
self.country_code_2 = country_code_2
self.country_code_3 = country_code_3
So weit, so gut, das funktioniert, genau wie erwartet.
Das einzige Problem, das ich hier habe, ist, dass wir einen Feldnamen jedes Mal geben müssen, wenn ein Feld deklariert wird. z.B. "country_code_2"
für das Feld country_code_2
.
Wie wäre es möglich, den Attributnamen der Modellklasse zu erhalten und in der Feldklasse zu verwenden?
Ich habe nach der Implementierung Ihrer Vorschläge ein Update hinzugefügt. Könnten Sie sich das ansehen? –
Sie verwenden 'six.with_metaclass()' nicht korrekt, es sollte als Basisklasse verwendet werden. Siehe http://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass. Sie können stattdessen damit beginnen, es nur mit Python 2 oder 3 zu arbeiten, bevor Sie 'six' verwenden :-) –
Ich habe' six.with_metaclass() 'durch' __metaclass__ = BaseModelMeta' ersetzt. (Ich benutze Python 2) Dies gibt den gleichen Fehler. –