python - para - ndb google app engine
¿Cómo puedo definir una propiedad única para un modelo en Google App Engine? (2)
Necesito algunas propiedades para ser único. ¿Cómo puedo conseguir esto?
¿Hay algo como unique=True
?
Estoy usando Google App Engine para Python.
Google ha proporcionado una función para hacer eso:
http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert
Model.get_or_insert(key_name, **kwds)
Intenta obtener la entidad del tipo de modelo con el nombre de clave proporcionado. Si existe, get_or_insert () simplemente lo devuelve. Si no existe, se crea, almacena y devuelve una nueva entidad con el tipo, nombre y parámetros dados en kwds.
El get y el posterior (posible) put están envueltos en una transacción para asegurar la atomicidad. Esto significa que get_or_insert () nunca sobrescribirá una entidad existente e insertará una nueva entidad si y solo si no existe ninguna entidad con el tipo y nombre dados.
En otras palabras, get_or_insert () es equivalente a este código de Python:
def txn():
entity = MyModel.get_by_key_name(key_name, parent=kwds.get(''parent''))
if entity is None:
entity = MyModel(key_name=key_name, **kwds)
entity.put()
return entity
return db.run_in_transaction(txn)
Argumentos:
nombre_clave El nombre de la clave de la entidad ** kwds Argumentos clave para pasar al constructor de la clase de modelo si no existe una instancia con el nombre de clave especificado. El argumento principal es obligatorio si la entidad deseada tiene un padre.
Nota: get_or_insert () no acepta un objeto RPC.
El método devuelve una instancia de la clase de modelo que representa la entidad solicitada, si existió o si fue creado por el método. Al igual que con todas las operaciones del almacén de datos, este método puede generar un TransactionFailedError si la transacción no pudo completarse.
No hay una restricción incorporada para garantizar que un valor sea único. Puedes hacer esto sin embargo:
query = MyModel.all(keys_only=True).filter(''unique_property'', value_to_be_used)
entity = query.get()
if entity:
raise Exception(''unique_property must have a unique value!'')
Utilizo keys_only=True
porque mejorará ligeramente el rendimiento al no obtener los datos de la entidad.
Un método más eficiente sería usar un modelo separado sin campos cuyo nombre de clave se compone de nombre de propiedad + valor. Entonces podría usar get_by_key_name
para obtener uno o más de estos nombres de claves compuestas y si obtiene uno o más valores not- None
, sabe que hay valores duplicados (y verificando qué valores no eran None
, sabrá cuáles no único.)
Como se mencionó uno por uno en los comentarios, estos enfoques -por su primer aspecto , más tarde por naturaleza- corren los riesgos de concurrencia. Teóricamente, una entidad podría crearse justo después de la verificación de un valor existente, y luego el código después de la verificación se ejecutará, lo que generará valores duplicados. Para evitar esto, deberá usar las transacciones: Transacciones - Google App Engine
Si está buscando verificar la singularidad en todas las entidades con transacciones, tendría que ponerlas todas en el mismo grupo utilizando el primer método, que sería muy ineficiente. Para transacciones, use el segundo método de esta manera:
class UniqueConstraint(db.Model):
@classmethod
def check(cls, model, **values):
# Create a pseudo-key for use as an entity group.
parent = db.Key.from_path(model.kind(), ''unique-values'')
# Build a list of key names to test.
key_names = []
for key in values:
key_names.append(''%s:%s'' % (key, values[key]))
def txn():
result = cls.get_by_key_name(key_names, parent)
for test in result:
if test: return False
for key_name in key_names:
uc = cls(key_name=key_name, parent=parent)
uc.put()
return True
return db.run_in_transaction(txn)
UniqueConstraint.check(...)
supondrá que cada par clave / valor único debe ser exclusivo para devolver el éxito. La transacción usará un solo grupo de entidades para cada tipo de modelo. De esta forma, la transacción es confiable para varios campos diferentes a la vez (para un solo campo, esto sería mucho más simple). Además, incluso si tiene campos con el mismo nombre en uno o más modelos, no entrarán en conflicto con El uno al otro.