Referenz zu Entitätsattributen

Cloud Datastore unterstützt eine Vielzahl von Datentypen für Attributwerte. Diese umfassen unter anderem:

  • Ganzzahlen
  • Gleitkommazahlen
  • Strings
  • Datumsangaben
  • Binärdaten

Eine vollständige Liste der Typen finden Sie unter Attribute und Werttypen.

Attribute und Werttypen

Die mit einer Entität verknüpften Datenwerte bestehen aus einem oder mehreren Attributen. Jedes Attribut hat einen Namen und einen oder mehrere Werte. Ein Attribut kann Werte mit mehr als einem Typ haben und zwei Entitäten können Werte unterschiedlichen Typs für dasselbe Attribut haben. Attribute können indexiert oder nicht indexiert sein. Abfragen, die nach einem Attribut A sortieren oder filtern, ignorieren Entitäten, bei denen A nicht indexiert ist. Eine Entität kann höchstens 20.000 indexierte Attribute haben.

Die folgenden Werttypen werden unterstützt:

Wenn eine Abfrage ein Attribut mit Werten gemischter Typen umfasst, verwendet Cloud Datastore eine deterministische Sortierung auf Basis der internen Darstellungen:

  1. Nullwerte
  2. Festkommazahlen
    • Ganzzahlen
    • Datums- und Uhrzeitwerte
  3. Boolesche Werte
  4. Bytesequenzen
    • Unicode-String
    • Blobstore-Schlüssel
  5. Gleitkommazahlen
  6. Cloud Datastore-Schlüssel

Da lange Textstrings und lange Bytestrings nicht indexiert werden, ist keine Reihenfolge definiert.

Attributtypen

NDB unterstützt die folgenden Attributtypen:

Attributtyp Beschreibung
IntegerProperty Vorzeichenbehaftete 64-Bit-Ganzzahl
FloatProperty Gleitkommazahl mit doppelter Genauigkeit
BooleanProperty Boolesch
StringProperty Unicode-String, bis zu 1.500 Bytes, indexiert
TextProperty Unicode-String, unbegrenzte Länge, nicht indexiert
BlobProperty Nicht interpretierter Byte-String:
wenn indexed=True mit bis zu 1.500 Byte festgelegt und indexiert wird;
wenn indexed mit dem Standardwert False und unbegrenzter Länge festgelegt und nicht indexiert wird
Optionales Schlüsselwortargument: compressed
DateTimeProperty Datum und Uhrzeit (siehe Datums- und Uhrzeitattribute)
DateProperty Datum (siehe Datums- und Uhrzeitattribute)
TimeProperty Zeit (siehe Datums- und Uhrzeitattribute)
GeoPtProperty Geografischer Ort. Dies ist ein ndb.GeoPt-Objekt. Das Objekt hat die Attribute lat und lon, beides Gleitkommazahlen. Sie können einen Ort mit zwei Gleitkommazahlen wie beispielsweise ndb.GeoPt(52.37, 4.88) oder mit einem String wie ndb.GeoPt("52.37, 4.88") angeben. Dies ist die gleiche Klasse wie db.GeoPt.
KeyProperty Cloud Datastore-Schlüssel
Optionales Schlüsselwortargument: kind=kind. Dieses legt fest, dass die Schlüssel, die diesem Attribut zugeordnet sind, immer die angegebene Art haben. Kann ein String oder eine abgeleitete Modellklasse sein.
BlobKeyProperty Blobstore-Schlüssel
Entspricht dem BlobReferenceProperty-Attribut in der alten DB API. Der Attributwert ist dabei BlobKey anstelle von BlobInfo. Mit BlobInfo(blobkey) können Sie BlobInfo erstellen.
UserProperty Nutzerobjekt.
StructuredProperty Enthält eine Modellart innerhalb einer anderen, nach Wert (siehe Strukturierte Attribute)
LocalStructuredProperty Entspricht dem Attribut StructuredProperty. Die Darstellung auf dem Laufwerk besteht aber aus einem intransparenten Blob und ist nicht indexiert (siehe Strukturierte Attribute).
Optionales Schlüsselwortargument: compressed
JsonProperty Der Wert ist ein Python-Objekt (z. B. eine Liste, ein Wörterbuch oder ein String), das mit dem Python-Modul json serialisiert werden kann. Cloud Datastore speichert die JSON-Serialisierung als Blob. Wird standardmäßig nicht indexiert.
Optionales Schlüsselwortargument: compressed
PickleProperty Der Wert ist ein Python-Objekt (z. B. eine Liste, ein Wörterbuch oder ein String), das mit dem Pickle-Protokoll von Python serialisiert werden kann. Cloud Datastore speichert die Pickle-Serialisierung als Blob. Wird standardmäßig nicht indexiert.
Optionales Schlüsselwortargument: compressed
GenericProperty Generischer Wert
Wird hauptsächlich von der Klasse Expando verwendet, kann aber auch explizit angewendet werden. Der Typ kann einer der folgenden sein: int, long, float, bool, str, unicode, datetime, Key, BlobKey, GeoPt, User, None.
ComputedProperty Wert, der von anderen Attributen durch eine benutzerdefinierte Funktion berechnet wird (siehe Berechnete Attribute)

Einige dieser Attribute haben das optionale Schlüsselwortargument compressed. Wenn das Attribut compressed=True enthält, werden ihre Daten mit gzip auf dem Laufwerk komprimiert. Dies beansprucht weniger Speicherplatz, benötigt aber CPU zum Codieren/Decodieren bei Schreib- und Lesevorgängen.

Sowohl die Komprimierung als auch die Dekomprimierung werden verzögert durchgeführt. Der Wert eines komprimierten Attributs wird erst beim ersten Zugriff dekomprimiert. Wird eine Entität, die einen komprimierten Attributwert enthält, gelesen und zurückgeschrieben, ohne auf das komprimierte Attribut zuzugreifen, wird es nicht dekomprimiert und auch nicht komprimiert. Der Kontext-Cache folgt ebenfalls diesem verzögerten Schema. Memcache speichert aber für komprimierte Attribute immer den komprimierten Wert.

Aufgrund der zusätzlichen CPU-Zeit, die für die Komprimierung benötigt wird, sollten komprimierte Attribute normalerweise nur dann verwendet werden, wenn die Daten zu groß sind, um ohne sie zu passen. Denken Sie daran, dass die gzip-basierte Komprimierung für Bilder und andere Mediendaten normalerweise keine Wirkung zeigt, da diese Formate bereits mit einem medienspezifischen Komprimierungsalgorithmus komprimiert wurden (z. B. JPEG bei Bildern).

Attributoptionen

Die meisten Attributtypen unterstützen einige Standardargumente. Das erste ist ein optionales Positionsargument, das den Cloud Datastore-Namen des Attributs angibt. Damit können Sie dem Attribut in Cloud Datastore einen anderen Namen als aus der Sicht der Anwendung zuweisen. Dies wird häufig zur Reduzierung des Speicherplatzes in Cloud Datastore eingesetzt, sodass Cloud Datastore abgekürzte Attributnamen verwenden kann, während Ihr Code längere, aussagekräftigere Codes verwendet. Beispiel:

class Employee(ndb.Model):
    full_name = ndb.StringProperty('n')
    retirement_age = ndb.IntegerProperty('r')

Dies ist besonders für wiederkehrende Attribute, für die Sie viele Werte pro Entität erwarten, von Vorteil.

Darüber hinaus unterstützen die meisten Attributtypen die folgenden Schlüsselwortargumente:

Argument Typ Standard Beschreibung
indexed bool Normalerweise True Fügen Sie ein Attribut in die Indexe von Cloud Datastore ein. Wird False festgelegt, können Werte nicht abgefragt werden, aber Schreibvorgänge sind schneller. Nicht alle Attributtypen unterstützen die Indexierung. Das Festlegen von indexed auf True schlägt für diese fehl.
Nicht indexierte Attribute benötigen weniger Schreibvorgänge als indexierte Attribute.
repeated bool False Der Attributwert ist eine Python-Liste, die Werte des zugrunde liegenden Typs enthält (siehe Wiederkehrende Attribute).
Kann nicht mit required=True oder default=True kombiniert werden
required bool False Für das Attribut muss ein Wert angegeben werden.
default Der zugrunde liegende Typ des Attributs Standardwert des Attributs, wenn keiner explizit angegeben ist
choices Liste der Werte des zugrunde liegenden Typs None Optionale Liste zulässiger Werte
validator Funktion None

Optionale Funktion, um den Wert zu validieren und möglicherweise zu erzwingen

Wird mit Argumenten (prop, value) aufgerufen und sollte entweder den (möglicherweise erzwungenen) Wert zurückgeben oder eine Ausnahme auslösen. Durch erneutes Aufrufen der Funktion für einen erzwungenen Wert darf der Wert nicht weiter geändert werden. (Beispiel: Wird value.strip() oder value.lower() zurückgegeben, so ist dies in Ordnung, wird value + '$' zurückgegeben, ist dies nicht in Ordnung.) Es kann auch None zurückgegeben werden, was "keine Änderung" bedeutet. Siehe auch Abgeleitete Attributklassen schreiben

verbose_name String None

Optionales HTML-Label zur Verwendung in Webformular-Frameworks wie jinja2

Wiederkehrende Attribute

Jedes Attribut mit repeated=True wird zu einem wiederkehrenden Attribut. Das Attribut verwendet eine Liste mit Werten des zugrunde liegenden Typs anstelle eines einzelnen Werts. Beispielsweise ist der Wert eines mit IntegerProperty(repeated=True) definierten Attributs eine Liste von Ganzzahlen.

Cloud Datastore kann mehrere Werte für ein solches Attributs anzeigen. Für jeden Wert wird ein separater Indexeintrag erstellt. Dies wirkt sich auf die Abfragesemantik aus. Ein Beispiel finden Sie unter Wiederkehrende Attribute abfragen.

In diesem Beispiel wird ein wiederkehrendes Attribut verwendet:

class Article(ndb.Model):
    title = ndb.StringProperty()
    stars = ndb.IntegerProperty()
    tags = ndb.StringProperty(repeated=True)
...
article = Article(
    title='Python versus Ruby',
    stars=3,
    tags=['python', 'ruby'])
article.put()

Dadurch wird eine Cloud Datastore-Entität mit folgendem Inhalt erstellt:

assert article.title == 'Python versus Ruby'
assert article.stars == 3
assert sorted(article.tags) == sorted(['python', 'ruby'])

Wenn Sie das Attribut tags abfragen, erfüllt diese Entität eine Abfrage nach 'python' oder 'ruby'.

Wenn Sie ein wiederkehrendes Attribut aktualisieren, können Sie ihm entweder eine neue Liste zuweisen oder die bestehende Liste ändern. Wenn Sie eine neue Liste zuweisen, werden die Typen der Listenelemente sofort validiert. Ungültige Elementtypen (z. B. die Zuweisung von [1, 2] zu art.tags oben) lösen eine Ausnahme aus. Wenn Sie die Liste verändern, wird die Änderung nicht sofort validiert. Stattdessen wird der Wert validiert, wenn Sie die Entität in Cloud Datastore schreiben.

Cloud Datastore behält die Reihenfolge der Listenelemente in einem wiederkehrenden Attribut bei, sodass Sie ihrer Reihenfolge eine Bedeutung zuweisen können.

Datums- und Uhrzeitattribute

Zum Speichern von Datums- und Zeitwerten stehen drei Attributtypen zur Verfügung:

  • DateProperty
  • TimeProperty
  • DateTimeProperty

Diese nutzen Werte, die zu den entsprechenden Klassen (date, time, datetime) des standardmäßigen Python-Moduls datetime gehören. Der allgemeinste Typ der drei ist DateTimeProperty, der sowohl ein Kalenderdatum als auch eine Uhrzeit anzeigt; die anderen sind gelegentlich nützlich für spezielle Zwecke, die nur ein Datum (wie ein Geburtsdatum) oder nur eine Uhrzeit (wie eine Besprechungszeit) erfordern. Aus technischen Gründen sind DateProperty und TimeProperty abgeleitete Klassen von DateTimeProperty. Sie sollten sich aber nicht auf diese Übernahmebeziehung verlassen (und beachten, dass sie sich von den Übernahmebeziehungen zwischen den vom Modul datetime selbst definierten zugrunde liegenden Klassen unterscheidet).

Hinweis: Die Uhrzeiten der App Engine werden immer in UTC (Coordinated Universal Time) ausgedrückt. Dies wird relevant, wenn Sie das aktuelle Datum oder die aktuelle Uhrzeit (datetime.datetime.now()) als Wert verwenden oder zwischen datetime-Objekten und POSIX-Zeitstempeln oder -Zeittupeln konvertieren. In Cloud Datastore sind aber keine expliziten Zeitzoneninformationen gespeichert. Wenn Sie also vorsichtig vorgehen, können Sie diese verwenden, um lokale Zeiten in einer beliebigen Zeitzone darzustellen – dabei müssen Sie die aktuelle oder die konvertierte Zeit verwenden.

Für jedes dieser Attribute gibt es zwei zusätzliche boolesche Schlüsselwortoptionen:

Option Beschreibung
auto_now_add Setzen Sie das Attribut auf das aktuelle Datum/die aktuelle Uhrzeit, wenn die Entität erstellt wird. Sie können dieses Attribut manuell überschreiben. Wenn die Entität aktualisiert wird, ändert sich das Attribut nicht. Verwenden Sie auto_now für dieses Verhalten.
auto_now Setzen Sie das Attribut auf das aktuelle Datum/die aktuelle Uhrzeit, wenn die Entität erstellt wird und wann immer sie aktualisiert wird.

Diese Optionen können nicht mit repeated=True kombiniert werden. Beide sind standardmäßig False; sind sie beide auf True gesetzt, hat auto_now Vorrang. Der Wert eines Attributs kann mit auto_now_add=True überschrieben werden, aber nicht ein Wert mit auto_now=True. Der automatische Wert wird erst generiert, wenn die Entität geschrieben wird. Das bedeutet, dass diese Optionen keine dynamischen Standardwerte bieten. (Diese Details unterscheiden sich von der alten DB-API.)

Hinweis: Wenn eine Transaktion, die ein Attribut mit auto_now_add=True schreibt, fehlschlägt und später noch einmal ausgeführt wird, gilt dafür dann der gleiche Zeitwert wie beim ursprünglichen Versuch. Der Wert wird nicht auf den Zeitpunkt des neuen Versuchs aktualisiert. Wenn die Transaktion dauerhaft fehlschlägt, wird der Wert des Attributs weiterhin in der im Arbeitsspeicher gespeicherten Kopie der Entität festgelegt.

Strukturierte Attribute

Sie können die Attribute eines Modells strukturieren. Beispielsweise können Sie eine Modellklasse "Contact" definieren, die eine Liste von Adressen mit jeweils interner Struktur enthält. Mit strukturierten Attributen vom Typ StructuredProperty ist dies möglich. Beispiel:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
guido = Contact(
    name='Guido',
    addresses=[
        Address(
            type='home',
            city='Amsterdam'),
        Address(
            type='work',
            street='Spear St',
            city='SF')])

guido.put()

Dadurch wird eine einzelne Cloud Datastore-Entität mit den folgenden Attributen erstellt:

assert guido.name == 'Guido'
addresses = guido.addresses
assert addresses[0].type == 'home'
assert addresses[1].type == 'work'
assert addresses[0].street is None
assert addresses[1].street == 'Spear St'
assert addresses[0].city == 'Amsterdam'
assert addresses[1].city == 'SF'

Das Zurücklesen einer solchen Entität rekonstruiert exakt die ursprüngliche Entität Contact. Obwohl die Instanzen Address mit der gleichen Syntax wie Modellklassen definiert sind, sind sie keine vollwertigen Entitäten. Sie haben keine eigenen Schlüssel in Cloud Datastore. Sie können nicht unabhängig von der Entität Contact abgerufen werden, zu der sie gehören. Eine Anwendung kann jedoch die Werte ihrer einzelnen Felder abfragen; siehe Filtern nach Werten strukturierter Attribute. Beachten Sie, dass address.type, address.street und address.city von Cloud Datastore als parallele Arrays eingestuft werden, die NDB-Bibliothek diesen Aspekt aber verbirgt und die entsprechende Liste der Instanzen Address erstellt.

Sie können für strukturierte Attribute bis auf indexed die gängigen Attributoptionen festlegen. Der Cloud Datastore-Name ist in diesem Fall das zweite Positionsargument (das erste ist die Modellklasse, die zum Definieren der Unterstruktur verwendet wird).

Wenn Sie die internen Attribute einer Unterstruktur nicht abfragen müssen, können Sie stattdessen ein lokales strukturiertes Attribut(LocalStructuredProperty) verwenden. Wenn Sie im obigen Beispiel StructuredProperty durch LocalStructuredProperty ersetzen, ist das Verhalten des Python-Codes identisch, aber Cloud Datastore erkennt bei jeder Adresse nur einen dunklen Blob. Die im Beispiel erstellte Entität guido wird folgendermaßen gespeichert: name = 'Guido' address = <dunkler Blob für {'type': 'home', 'city': 'Amsterdam'}> address = <dunkler Blob für {'type': 'work', 'city': 'SF', 'street': 'Spear St'}>

Die Entität wird korrekt zurückgelesen. Da Attribute dieses Typs immer nicht indexiert sind, können Sie keine Adresswerte abfragen.

Hinweis: Ein Attribut StructuredProperty mit einem verschachtelten Attribut unterstützt nur eine einzige Ebene mit wiederkehrenden Attributen, unabhängig davon, ob es strukturiert ist. Die StructuredProperty kann wiederholt werden oder das verschachtelte Attribut kann wiederholt werden, aber nicht beide. Zur Umgehung des Problems kann LocalStructuredProperty verwendet werden, das diese Einschränkung nicht aufweist (aber keine Abfragen für seine Attributwerte zulässt).

Berechnete Attribute

Berechnete Attribute (ComputedProperty) sind schreibgeschützte Attribute, deren Werte aus anderen Attributwerten durch eine von einer Anwendung bereitgestellte Funktion berechnet werden. Beachten Sie, dass ein berechnetes Attribut nur die Typen unterstützt, die von generischen Attributen unterstützt werden. Der berechnete Wert wird in Cloud Datastore geschrieben, sodass er im Cloud Datastore-Viewer abgefragt und angezeigt werden kann. Der gespeicherte Wert wird aber ignoriert, wenn die Entität aus Cloud Datastore zurückgelesen wird. Vielmehr wird der Wert neu berechnet, indem die Funktion immer dann aufgerufen wird, wenn der Wert angefragt wird. Beispiel:

class SomeEntity(ndb.Model):
    name = ndb.StringProperty()
    name_lower = ndb.ComputedProperty(lambda self: self.name.lower())
...
entity = SomeEntity(name='Nick')
entity.put()

So wird eine Entität mit den folgenden Attributwerten gespeichert:

assert entity.name == 'Nick'
assert entity.name_lower == 'nick'

Wenn wir den Namen in "Nickie" ändern und den Wert von name_lower abfragen, wird "nickie" zurückgegeben:

entity.name = 'Nick'
assert entity.name_lower == 'nick'
entity.name = 'Nickie'
assert entity.name_lower == 'nickie'

Hinweis: Verwenden Sie ComputedProperty, wenn die Anwendung den berechneten Wert abfragt. Wenn Sie nur die abgeleitete Version in Python-Code verwenden möchten, definieren Sie eine reguläre Methode oder verwenden Sie das integrierte @property von Python.

Hinweis: Wenn Sie ein Modell erstellen, ohne manuell einen Schlüssel anzugeben, und stattdessen Cloud Datastore zum automatischen Generieren der Entitäts-ID verwenden, kann ein ComputedProperty-Attribut das ID-Feld beim ersten put()-Aufruf nicht lesen. Dies liegt daran, dass das Feld berechnet wird, bevor die ID generiert wird. Wenn Sie ein ComputedProperty-Attribut verwenden, das die ID der Entität benötigt, können Sie mit der Methode allocate_ids eine ID und einen Schlüssel für das Erstellen der Entität generieren. Mit dem ComputedProperty-Attribut kann dann beim ersten put()-Aufruf der Entität auf diese ID verwiesen werden.

Google Protocol RPC – Nachrichtenattribute

Die Google Protocol RPC-Bibliothek verwendet Message-Objekte für strukturierte Daten. Diese können RPC-Anfragen und -Antworten, aber auch andere Elemente darstellen. NDB bietet eine API zum Speichern der Objekte Message von Google Protocol RPC als Entitäts-Attribute. Beispiel: Sie definieren eine abgeleitete Message-Klasse:

from protorpc import messages
...
class Note(messages.Message):
    text = messages.StringField(1, required=True)
    when = messages.IntegerField(2)

Sie können die Objekte Note mithilfe der NDB-API msgprop in Cloud Datastore als Entitätsattributwert speichern.

from google.appengine.ext import ndb
from google.appengine.ext.ndb import msgprop
...
class NoteStore(ndb.Model):
    note = msgprop.MessageProperty(Note, indexed_fields=['when'])
    name = ndb.StringProperty()
...
my_note = Note(text='Excellent note', when=50)

ns = NoteStore(note=my_note, name='excellent')
key = ns.put()

new_notes = NoteStore.query(NoteStore.note.when >= 10).fetch()

Wenn Sie Feldnamen abfragen möchten, müssen diese indexiert werden. Sie können eine Liste von Feldnamen angeben, die mit dem Parameter indexed_fields für MessageProperty indexiert werden.

MessageProperty unterstützt eine Reihe von Attributoptionen, jedoch nicht alle. Unterstützt werden:

  • name
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

Nachrichtenattribute unterstützen nicht die Attributoption indexed. Sie können Message-Werte nicht indexieren. (Sie können Felder einer Nachricht wie oben beschrieben indexieren.)

Das funktioniert auch für mit MessageField verschachtelte Nachrichten:

class Notebook(messages.Message):
    notes = messages.MessageField(Note, 1, repeated=True)
...
class SignedStorableNotebook(ndb.Model):
    author = ndb.StringProperty()
    nb = msgprop.MessageProperty(
        Notebook, indexed_fields=['notes.text', 'notes.when'])

MessageProperty hat die spezielle Attributoption protocol, die angibt, wie das Nachrichtenobjekt in Cloud Datastore serialisiert wird. Deren Werte sind Protokollnamen, wie sie von der Klasse protorpc.remote.Protocols verwendet werden. Unterstützte Protokollnamen sind protobuf und protojson; der Standardwert ist protobuf.

msgprop definiert außerdem den Attributtyp EnumProperty, mit dem ein protorpc.messages.Enum-Wert in einer Entität gespeichert werden kann. Beispiel:

class Color(messages.Enum):
    RED = 620
    GREEN = 495
    BLUE = 450
...
class Part(ndb.Model):
    name = ndb.StringProperty()
    color = msgprop.EnumProperty(Color, required=True)
...
p1 = Part(name='foo', color=Color.RED)
print p1.color  # prints "RED"

EnumProperty speichert den Wert als Ganzzahl, EnumProperty ist außerdem eine abgeleitete Klasse von IntegerProperty. Dies bedeutet, dass Sie Ihre Enum-Werte umbenennen können, ohne bereits gespeicherte Entitäten ändern zu müssen. Sie können sie jedoch nicht neu nummerieren.

EnumProperty unterstützt die folgenden Attributoptionen:

  • name
  • indexed
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

Weitere Informationen zu NDB-Entitätsmodellen

Ein NDB-Entitätsmodell kann Attribute definieren. Entitätsattribute sind ungefähr wie Datenelemente bei Python-Klassen, eine strukturierte Methode zum Speichern von Daten; sie ähneln auch Feldern in einem Datenbankschema.

Eine typische Anwendung definiert ein Datenmodell durch die Definition einer Klasse, die Werte von Model mit Klassenattributen übernimmt. Beispiel:


from google.appengine.ext import ndb
...
class Account(ndb.Model):
    username = ndb.StringProperty()
    userid = ndb.IntegerProperty()
    email = ndb.StringProperty()

Hier sind username, userid und email Attribute von Account.

Es gibt mehrere andere Attributtypen. Einige eignen sich gut für die Darstellung von Daten und Zeiten und haben praktische automatische Updatefunktionen.

In einer Anwendung kann das Verhalten eines Attributs angepasst werden. Dazu müssen Optionen für das Attribut festgelegt werden. Diese können die Validierung vereinfachen, Standardwerte bestimmen oder die Indexierung von Abfragen ändern.

Ein Modell kann komplexe Attribute haben. Wiederkehrende Attribute sind listenähnlich. Strukturierte Attribute sind objektähnlich. Schreibgeschützte berechnete Attribute werden über Funktionen definiert; so kann ein Attribut in Bezug auf eine oder mehrere andere Attribute mühelos definiert werden. Expando-Modelle können Attribute dynamisch definieren.