Referenz zu Entitätsattributen

Firestore im Datastore-Modus (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 verschiedener Typen enthält, verwendet Datastore eine deterministische Sortierung anhand der internen Darstellungen:

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

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

Attributtypen

NDB unterstützt die folgenden Attributtypen:

AttributtypBeschreibung
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 Bytestring:
Wenn Sie indexed=True festlegen, bis zu 1500 Byte, indexiert;
wenn indexed gleich False (Standard) ist, unbegrenzte Länge, nicht indexiert.
Optionales Keyword-Argument: 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, beide Gleitkommazahlen. Sie können eines mit zwei Gleitkommazahlen wie ndb.GeoPt(52.37, 4.88) oder einem String ndb.GeoPt("52.37, 4.88") erstellen. (Dies ist die gleiche Klasse wie db.GeoPt)
KeyProperty Datastore-Schlüssel
Das optionale Keyword-Argument: kind=kind macht es erforderlich, dass Schlüssel, die diesem Attribut zugewiesen sind, immer die angegebene Art aufweisen. Kann ein String oder eine abgeleitete Modellklasse sein.
BlobKeyProperty Blobstore-Schlüssel
Entspricht BlobReferenceProperty in der alten Database API, aber der Attributwert ist 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 Keyword-Argument: compressed.
JsonProperty Der Wert ist ein Python-Objekt (z. B. eine Liste, ein Wörterbuch oder ein String), das mit dem json-Modul von Python serialisiert werden kann. Datastore speichert die JSON-Serialisierung als Blob. Wird standardmäßig nicht indexiert.
Optionales Keyword-Argument: 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. Datastore speichert die Pickle-Serialisierung als Blob. Wird standardmäßig nicht indexiert.
Optionales Keyword-Argument: compressed.
GenericProperty Allgemeiner Wert
Wird hauptsächlich von der Klasse Expando verwendet, ist aber auch explizit verwendbar. Der Typ kann int, long, float, bool, str, unicode, datetime, Key, BlobKey, GeoPt, User oder None sein.
ComputedProperty Wert, der von anderen Attributen durch eine benutzerdefinierte Funktion berechnet wird (siehe Berechnete Attribute)

Einige dieser Attribute haben das optionale Keyword-Argument compressed. Wenn das Attribut compressed=True enthält, werden die 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 Datastore-Namen des Attributs angibt. Damit können Sie dem Attribut in Datastore einen anderen Namen geben als aus Sicht der Anwendung. Dies wird häufig zur Reduzierung des Speicherplatzes in 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 TypStandardeinstellung Beschreibung
indexed bool Normalerweise True Eigenschaft in die Datenspeicherindex einschließen; Wenn False, können Werte nicht abgefragt werden, aber Schreibvorgänge sind schneller. Nicht alle Property-Typen unterstützen die Indexierung. die Einstellung indexed bis True schlägt 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 FunktionNone

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. Die Rückgabe von value.strip() oder value.lower() ist beispielsweise zulässig, aber nicht value + '$'. Es kann auch None zurückgegeben werden, was "keine Änderung" bedeutet. Siehe auch Abgeleitete Attributklassen schreiben

verbose_name StringNone

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. Der Wert eines mit IntegerProperty(repeated=True) definierten Attributs ist beispielsweise eine Liste ganzer Zahlen.

Der Datenspeicher kann für eine solche Eigenschaft mehrere Werte sehen. 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 Datenspeicherentität mit folgendem Inhalt erstellt:

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

Bei der Abfrage des Attributs tags erfüllt diese Entität eine Abfrage für '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 Datastore schreiben.

Datastore behält die Reihenfolge der Listenelemente in einem wiederkehrenden Attribut bei. Die Reihenfolge ergibt für Sie also einen Sinn.

Datums- und Uhrzeitattribute

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

  • DateProperty
  • TimeProperty
  • DateTimeProperty

Diese übernehmen Werte, die zu den entsprechenden Klassen (date, time, datetime) des Python-Standardmoduls datetime gehören. Die allgemeinste der drei ist DateTimeProperty, die sowohl ein Kalenderdatum als auch eine Uhrzeit angibt; die anderen sind gelegentlich für spezielle Zwecke nützlich, bei denen nur ein Datum (z. B. ein Geburtsdatum) oder nur eine Uhrzeit (z. B. eine Besprechungszeit) erforderlich ist. 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 ist relevant, wenn Sie das aktuelle Datum oder die aktuelle Uhrzeit (datetime.datetime.now()) als Wert verwenden oder zwischen Datum/Uhrzeit-Objekten und POSIX-Zeitstempeln oder -Tupeln konvertieren. Es werden jedoch keine expliziten Zeitzoneninformationen in Datastore gespeichert. Wenn Sie also vorsichtig sind, können Sie diese verwenden, um Ortszeiten in jeder Zeitzone darzustellen, wenn Sie die aktuelle Zeit oder die Konvertierungen verwenden.

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

OptionBeschreibung
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 für dieses Verhalten auto_now.
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 auf False gesetzt. Wenn beide auf True gesetzt sind, hat auto_now Vorrang. Der Wert eines Attributs kann mit auto_now_add=True überschrieben werden, aber nicht für eines 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 wiederholt wird, wird derselbe Zeitwert wie beim ursprünglichen Versuch verwendet, anstatt ihn auf den Zeitpunkt der Wiederholung zu aktualisieren. 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 Datenspeicherentität mit den folgenden Eigenschaften 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 Address-Instanzen mit derselben Syntax wie für Modellklassen definiert werden, sind sie keine vollwertigen Entitäten. Sie haben keine eigenen Schlüssel in 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 Nach Werten für strukturierte Attribute filtern. address.type, address.street und address.city werden aus Sicht von Datastore als parallele Arrays angesehen, aber die NDB-Bibliothek blendet diesen Aspekt aus und erstellt die entsprechende Liste von Address-Instanzen.

Sie können die üblichen Attributoptionen für strukturierte Attribute angeben (außer indexed). Der 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 Datastore sieht nur ein undurchsichtiges Blob für jede Adresse. Die im Beispiel erstellte Entität guido würde so gespeichert: name = 'Guido' adresse = <undurchsichtiger Blob für {'type': 'home', 'city': 'Amsterdam'}> address = <undurchsichtiger Blob für {"type": "work", "city": "SF", "street": "Speer St"}>

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

Hinweis:: Ein StructuredProperty mit einem verschachtelten Attribut unterstützt nur eine einzige Ebene mit wiederkehrenden Attributen, unabhängig davon, ob es strukturiert ist. Das StructuredProperty oder das verschachtelte Attribut kann wiederholt werden, aber nicht beide. Eine Problemumgehung ist die Verwendung von LocalStructuredProperty, das diese Einschränkung nicht aufweist, aber keine Abfragen der zugehörigen Attributwerte zulässt.

Berechnete Attribute

Berechnete Attribute (ComputedProperty) sind schreibgeschützte Attribute, deren Wert aus anderen Attributwerten durch eine von der Anwendung bereitgestellte Funktion berechnet wird. Beachten Sie, dass ein berechnetes Attribut nur die Typen unterstützt, die von generischen Attributen unterstützt werden. Der berechnete Wert wird in Datastore geschrieben, sodass er abgefragt und im Datastore-Betrachter angezeigt werden kann. Der gespeicherte Wert wird jedoch ignoriert, wenn die Entität aus Datastore zurückgelesen wird. Stattdessen wird der Wert neu berechnet, indem die Funktion immer dann aufgerufen wird, wenn der Wert angefordert 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 nach dem Wert von name_lower fragen, 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 im Python-Code verwenden möchten, definieren Sie eine reguläre Methode oder verwenden Sie die integrierte Funktion @property von Python.

Hinweis:: Wenn Sie ein Modell erstellen, ohne manuell einen Schlüssel anzugeben, und stattdessen Datastore zum automatischen Generieren der Entitäts-ID verwenden, kann ein ComputedProperty 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 benötigen, das die ID der Entität verwendet, 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 kann dann beim ersten put()-Aufruf auf diese ID verwiesen werden.

Google Protocol RPC – Nachrichtenattribute

Die Google Protocol RPC-Bibliothek verwendet Message-Objekte für strukturierte Daten. Sie können RPC-Anfragen, -Antworten oder andere Dinge darstellen. NDB bietet eine API zum Speichern der Message-Objekte von Google Protocol RPC als Entitätsattribute. Angenommen, Sie definieren eine Message - Unterklasse:

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

Sie können Note-Objekte in Datastore als Entitätsattribute speichern, indem Sie die msgprop API von NDB verwenden.

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 mit Feldnamen angeben, die mit dem Parameter indexed_fields bis MessageProperty indexiert werden.

MessageProperty unterstützt viele, aber nicht alle Attributoptionen. Unterstützt werden:

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

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

Verschachtelte Nachrichten (mit MessageField) funktionieren auch:

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 Datastore serialisiert wird. Die Werte sind Protokollnamen, die von der Klasse protorpc.remote.Protocols verwendet werden. Unterstützte Protokollnamen sind protobuf und protojson; der Standardwert ist protobuf.

msgprop definiert auch EnumProperty, einen Attributtyp, der zum Speichern eines protorpc.messages.Enum-Werts in einer Entität verwendet 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. Tatsächlich ist EnumProperty 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, indem sie eine Klasse definiert, die von Model mit einigen Attributen der Attributklasse ü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.